diff options
| author | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
|---|---|---|
| committer | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
| commit | 1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch) | |
| tree | bf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /AVStream/sampledevicemft | |
| parent | da21c8784c83c5fd614f3030323e229d6a5fb10e (diff) | |
Fix cases
Diffstat (limited to 'AVStream/sampledevicemft')
19 files changed, 8454 insertions, 0 deletions
diff --git a/AVStream/sampledevicemft/SampleDeviceMft.sln b/AVStream/sampledevicemft/SampleDeviceMft.sln new file mode 100644 index 00000000..a6a00c4d --- /dev/null +++ b/AVStream/sampledevicemft/SampleDeviceMft.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multipinmft", "multipinmft.vcxproj", "{E77657CD-A270-49E1-823A-8A14FF8596C8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.ActiveCfg = Debug|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.Build.0 = Debug|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.ActiveCfg = Release|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.Build.0 = Release|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.ActiveCfg = Debug|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.Build.0 = Debug|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.ActiveCfg = Release|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/AVStream/sampledevicemft/Source.def b/AVStream/sampledevicemft/Source.def new file mode 100644 index 00000000..752ef2ea --- /dev/null +++ b/AVStream/sampledevicemft/Source.def @@ -0,0 +1,5 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DllGetClassObject PRIVATE diff --git a/AVStream/sampledevicemft/basepin.cpp b/AVStream/sampledevicemft/basepin.cpp new file mode 100644 index 00000000..a1f71860 --- /dev/null +++ b/AVStream/sampledevicemft/basepin.cpp @@ -0,0 +1,847 @@ +#include "stdafx.h" +#include "common.h" +#include "multipinmft.h" +#include "multipinmfthelpers.h" +#include "basepin.h" + +#ifdef MF_WPP +#include "basepin.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif +/* -------> New STATE + | + |old State +DeviceStreamState_Stop DeviceStreamState_Pause DeviceStreamState_Run DeviceStreamState_Disabled +DeviceStreamState_Pause +DeviceStreamState_Run +DeviceStreamState_Disabled +*/ + +DeviceStreamState pinStateTransition[4][4] = { + { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled }, + { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled }, + { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled }, + { DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled } +}; + +CBasePin::CBasePin( _In_ ULONG id, _In_ CMultipinMft *parent) : + m_StreamId(id) + , m_Parent(parent) + , m_setMediaType(nullptr) +{ + +} + +CBasePin::~CBasePin() +{ + IMFMediaType *pMediaType = nullptr; + for ( ULONG ulIndex = 0, ulSize = (ULONG)m_listOfMediaTypes.size(); ulIndex < ulSize; ulIndex++ ) + { + pMediaType = m_listOfMediaTypes[ulIndex]; + SAFE_RELEASE(pMediaType); + } + m_listOfMediaTypes.clear(); + m_spAttributes = nullptr; +} + +HRESULT CBasePin::AddMediaType( _Inout_ DWORD *pos, _In_ IMFMediaType *pMediaType) +{ + HRESULT hr = S_OK; + CAutoLock Lock(lock()); + DMFTCHECKNULL_GOTO(pMediaType, done, E_INVALIDARG); + + hr = ExceptionBoundary([&]() + { + m_listOfMediaTypes.push_back(pMediaType); + }); + + DMFTCHECKHR_GOTO(hr, done); + pMediaType->AddRef(); + + if (pos) + { + *pos = (DWORD)(m_listOfMediaTypes.size() - 1); + } + +done: + return hr; +} + +HRESULT CBasePin::GetMediaTypeAt( _In_ DWORD pos, _Outptr_result_maybenull_ IMFMediaType **ppMediaType ) +{ + HRESULT hr = S_OK; + CAutoLock Lock(lock()); + DMFTCHECKNULL_GOTO(ppMediaType,done,E_INVALIDARG); + + if (pos >= m_listOfMediaTypes.size()) + { + DMFTCHECKHR_GOTO(MF_E_NO_MORE_TYPES,done); + } + *ppMediaType = m_listOfMediaTypes[pos]; + if (*ppMediaType) + { + (*ppMediaType)->AddRef(); + } +done: + return hr; +} + +STDMETHODIMP_(BOOL) CBasePin::IsMediaTypeSupported +( + _In_ IMFMediaType *pMediaType, + _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_) + IMFMediaType **ppIMFMediaTypeFull +) +{ + HRESULT hr = S_OK; + BOOL bFound = FALSE; + CAutoLock Lock(lock()); + DMFTCHECKNULL_GOTO(pMediaType,done,E_INVALIDARG); + if (ppIMFMediaTypeFull) + { + *ppIMFMediaTypeFull = nullptr; + } + + for (UINT uIIndex = 0, uISize = (UINT)m_listOfMediaTypes.size(); uIIndex < uISize ; uIIndex++ ) + { + DWORD dwResult = 0; + hr = m_listOfMediaTypes[ uIIndex ]->IsEqual( pMediaType, &dwResult ); + if (hr == S_FALSE) + { + + if ((dwResult & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) && + (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_TYPES) && + (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_DATA)) + { + hr = S_OK; + } + } + if (hr == S_OK) + { + bFound = TRUE; + if (ppIMFMediaTypeFull) { + *ppIMFMediaTypeFull = m_listOfMediaTypes[uIIndex]; + (*ppIMFMediaTypeFull)->AddRef(); + } + break; + } + else if (FAILED(hr)) + { + DMFTCHECKHR_GOTO(hr,done); + } + } +done: + return SUCCEEDED(hr) ? TRUE : FALSE; +} + + +STDMETHODIMP CBasePin::GetOutputAvailableType(_In_ DWORD dwTypeIndex, _Out_opt_ IMFMediaType** ppType) +{ + return GetMediaTypeAt( dwTypeIndex, ppType ); +} + + +HRESULT CBasePin::QueryInterface( + _In_ REFIID iid, + _Outptr_result_maybenull_ void** ppv + ) +{ + HRESULT hr = S_OK; + + DMFTCHECKNULL_GOTO(ppv, out, E_POINTER); + + *ppv = nullptr; + + if ( iid == __uuidof( IUnknown ) ) + { + *ppv = static_cast<VOID*>(this); + AddRef(); + } + else + if ( iid == __uuidof( IMFAttributes ) ) + { + *ppv = static_cast< IMFAttributes* >( this ); + AddRef(); + } + else + if ( iid == __uuidof( IKsControl ) ) + { + *ppv = static_cast< IKsControl* >( this ); + AddRef(); + } + else + { + hr = E_NOINTERFACE; + } +out: + return hr; +} + + + + +// +//Input Pin implementation +// +CInPin::CInPin( + _In_opt_ IMFAttributes *pAttributes, + _In_ ULONG ulPinId, + _In_ CMultipinMft *pParent) + : + CBasePin(ulPinId, pParent), + m_stStreamType(GUID_NULL), + m_activeStreamCount(0), + m_state(DeviceStreamState_Stop), + m_prefferedMediaType(nullptr), + m_waitInputMediaTypeWaiter(NULL), + m_preferredStreamState(DeviceStreamState_Stop) +{ + setAttributes(pAttributes); +} + + + +CInPin::~CInPin() +{ + setAttributes( nullptr ); + m_spSourceTransform = nullptr; + + for (ULONG ulIndex = 0, ulSize = (ULONG)m_outpins.size(); + ulIndex < ulSize; + ulIndex++) + { + CBasePin *pPin = m_outpins[ulIndex]; + SAFERELEASE(pPin); + } + if (m_waitInputMediaTypeWaiter) + { + CloseHandle(m_waitInputMediaTypeWaiter); + } + +} + + + +STDMETHODIMP CInPin::Init( + _In_ IMFTransform* pTransform + ) +{ + + HRESULT hr = S_OK; + + DMFTCHECKNULL_GOTO( pTransform, done, E_INVALIDARG ); + + m_spSourceTransform = pTransform; + + DMFTCHECKHR_GOTO( GetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType ), done ); + + // + //Get the DevProxy IKSControl.. used to send the KSControls or the device control IOCTLS over to devproxy and finally on to the driver!!!! + // + DMFTCHECKHR_GOTO( m_spAttributes.As( &m_spIkscontrol ), done ); + + m_waitInputMediaTypeWaiter = CreateEvent( NULL, + FALSE, + FALSE, + TEXT("MediaTypeWaiter") + ); + DMFTCHECKNULL_GOTO( m_waitInputMediaTypeWaiter, done, E_OUTOFMEMORY ); + + DMFTCHECKHR_GOTO( GenerateMFMediaTypeListFromDevice(streamId()),done ); + +done: + if ( FAILED(hr) ) + { + m_spSourceTransform = nullptr; + + if ( m_waitInputMediaTypeWaiter ) + { + CloseHandle( m_waitInputMediaTypeWaiter ); + m_waitInputMediaTypeWaiter = NULL; + } + + m_stStreamType = GUID_NULL; + } + + return hr; +} + + +STDMETHODIMP CInPin::GenerateMFMediaTypeListFromDevice( + _In_ UINT uiStreamId + ) +{ + HRESULT hr = S_OK; + GUID stSubType = { 0 }; + //This is only called in the begining when the input pin is constructed + DMFTCHECKNULL_GOTO( m_spSourceTransform, done, MF_E_TRANSFORM_TYPE_NOT_SET ); + for (UINT iMediaType = 0; SUCCEEDED(hr) ; iMediaType++) + { + ComPtr<IMFMediaType> spMediaType; + DWORD pos = 0; + + hr = m_spSourceTransform->MFTGetOutputAvailableType(uiStreamId, iMediaType, spMediaType.GetAddressOf()); + if (hr != S_OK) + break; + + DMFTCHECKHR_GOTO(AddMediaType(&pos, spMediaType.Get()), done); + } +done: + if (hr == MF_E_NO_MORE_TYPES) { + hr = S_OK; + } + return hr; +} + +STDMETHODIMP CInPin::SendSample( + _In_ IMFSample *pSample + ) +{ + HRESULT hr = S_OK; + BOOL sentOne = TRUE; + DMFTCHECKNULL_GOTO(pSample, done, S_OK); + + for ( ULONG ulIndex = 0, ulSize = (ULONG) m_outpins.size(); ulIndex < ulSize; ulIndex++ ) + { + COutPin *poPin = (COutPin *)m_outpins[ ulIndex ]; + + pSample->AddRef(); + + if (FAILED(hr = poPin->AddSample(pSample, this))) + { + pSample->Release(); + } + sentOne = (sentOne || SUCCEEDED(hr)); + } +done: + return sentOne ? S_OK : E_FAIL; +} + +STDMETHODIMP_(VOID) CInPin::ConnectPin( _In_ CBasePin * poPin ) +{ + CAutoLock Lock(lock()); + if (poPin!=nullptr) + { + m_outpins.push_back(poPin); + poPin->AddRef(); + } +} + +STDMETHODIMP_(DeviceStreamState) CInPin::GetState() +{ + return m_state; +} + +STDMETHODIMP_(DeviceStreamState) CInPin::SetState( _In_ DeviceStreamState state ) +{ + return (DeviceStreamState)InterlockedExchange((LONG*)&m_state, state ); +} + +STDMETHODIMP CInPin::WaitForSetInputPinMediaChange() +{ + DWORD dwWait = 0; + HRESULT hr = S_OK; + + dwWait = WaitForSingleObject( m_waitInputMediaTypeWaiter, INFINITE ); + + if ( dwWait != WAIT_OBJECT_0 ) + { + hr = E_FAIL; + goto done; + } +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CInPin::GetInputStreamPreferredState( + _Inout_ DeviceStreamState* value, + _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType + ) +{ + HRESULT hr = S_OK; + CAutoLock Lock(lock()); + + if (value!=nullptr) + { + *value = m_preferredStreamState; + } + + if (ppMediaType ) + { + *ppMediaType = nullptr; + if ( m_prefferedMediaType != nullptr ) + { + m_prefferedMediaType.CopyTo(ppMediaType); + } + } + + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +HRESULT CInPin::SetInputStreamState( + _In_ IMFMediaType* pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags + ) +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwFlags); + + CAutoLock Lock(lock()); + // + //Set the media type + // + + setMediaType(pMediaType); + SetState(value); + + // + //Set the event. This event is being waited by an output media/state change operation + // + + m_prefferedMediaType = nullptr; + SetEvent(m_waitInputMediaTypeWaiter); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +// +//Output Pin Implementation +// +COutPin::COutPin( + _In_ ULONG ulPinId, + _In_opt_ CMultipinMft *pparent, + _In_ IKsControl* pIksControl + ) + : CBasePin( ulPinId, pparent ), + m_firstSample( false ) +{ + HRESULT hr = S_OK; + CPinState* pState = NULL; + ComPtr<IMFAttributes> spAttributes; + + for ( ULONG ulIndex = 0; ulIndex <= DeviceStreamState_Disabled; ulIndex++ ) + { + switch ( ulIndex ) + { + + case DeviceStreamState_Run: + pState = ( CPinState* )new CPinOpenState(this); + DMFTCHECKNULL_GOTO(pState, done, E_OUTOFMEMORY); + break; + case DeviceStreamState_Pause: + case DeviceStreamState_Stop: + case DeviceStreamState_Disabled: + //Currently both the closed and the drain state behave similarly + pState = ( CPinState* )new CPinClosedState(); + DMFTCHECKNULL_GOTO(pState, done, E_OUTOFMEMORY); + break; + } + + m_states.push_back( pState ); + + m_state = m_states[ DeviceStreamState_Stop ]; + } + // + //Get the input pin IKS control.. the pin IKS control talks to sourcetransform's IKS control + // + m_spIkscontrol = pIksControl; + + MFCreateAttributes( &spAttributes, 3 ); //Create the space for the attribute store!! + setAttributes( spAttributes.Get()); + DMFTCHECKHR_GOTO( SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ), done ); + DMFTCHECKHR_GOTO( SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"Sample_CameraExtensionMft" ),done ); + DMFTCHECKHR_GOTO( SetUINT32( MF_TRANSFORM_ASYNC, TRUE ),done ); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); +} + +COutPin::~COutPin() +{ + CPinQueue *que = NULL; + m_spAttributes = nullptr; + + for ( ULONG ulIndex = 0, ulSize = (ULONG)m_queues.size(); ulIndex < ulSize; ulIndex++ ) + { + que = m_queues[ ulIndex ]; + delete(que); + que = NULL; + } + CPinState *pinState = NULL; + for (ULONG ulIndex = 0, ulSize = (ULONG)m_states.size(); ulIndex < ulSize; ulIndex++) + { + pinState = m_states[ ulIndex ]; + delete( pinState ); + pinState = NULL; + } + m_states.clear(); + m_queues.clear(); +} + +/*++ +COutPin::AddPin +Description: +Called from AddSample if the Output Pin is in open state. This function looks for the queue +corresponding to the input pin and adds it in the queue. +--*/ +STDMETHODIMP COutPin::AddPin( + _In_ DWORD inputPinId + ) +{ + // + //Add a new queue corresponding to the input pin + // + HRESULT hr = S_OK; + CAutoLock Lock(lock()); + + CPinQueue *que = new (std::nothrow) CPinQueue(inputPinId); + DMFTCHECKNULL_GOTO( que, done, E_OUTOFMEMORY ); + hr = ExceptionBoundary([&]() + { + (void)m_queues.push_back(que); + }); + DMFTCHECKHR_GOTO(hr, done); + // + //Just ramdonmize media types for odd numbered pins + // + if ( streamId() != 0 && streamId() % 2 != 0 ) + { + RandomnizeMediaTypes(m_listOfMediaTypes); + } + +done: + + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return S_OK; +} + +/*++ +COutPin::AddSampleInternal +Description: +Called from AddSample if the Output Pin is in open state. This function looks for the queue +corresponding to the input pin and adds it in the queue. +--*/ + +STDMETHODIMP COutPin::AddSampleInternal( _In_ IMFSample *pSample, _In_ CBasePin *pPin ) +{ + BOOL res = true; + CAutoLock Lock( lock() ); + + for ( DWORD dwIndex = 0, dwSize = (DWORD)m_queues.size(); dwIndex < dwSize; dwIndex++ ) + { + // + //This output pin maybe connected to multiple input pins + //Only insert into the corresponding queue to the input pin on which the + //sample is received + // + if (m_queues[dwIndex]->pinStreamId() == pPin->streamId()) + { + if (! m_queues[ dwIndex ]->Insert( pSample ) ) + { + res |= false; + } + + } + } + return res ? S_OK : E_FAIL; +} + +/*++ +COutPin::AddSample +Description: +Called when ProcessInput is called on the Device Transform. The Input Pin puts the samples +in the pins connected. If the Output pins are in open state the sample lands in the queues +--*/ + +STDMETHODIMP COutPin::AddSample( _In_ IMFSample *pSample, _In_ CBasePin *pPin) +{ + HRESULT hr = S_OK; + CAutoLock lock( lock() ); + + DMFTCHECKHR_GOTO( m_state->Open(), done ); + + DMFTCHECKHR_GOTO( AddSampleInternal( pSample, pPin ),done ); + +done: + return hr; +} + +/*++ +COutPin::SetState +Description: +State setter for the output pin +--*/ +STDMETHODIMP_(VOID) COutPin::SetFirstSample( + _In_ BOOL fisrtSample ) +{ + m_firstSample = fisrtSample; +} + +/*++ +COutPin::GetState +Description: +State getter for the output pin +--*/ +DeviceStreamState COutPin::GetState() +{ + return m_state->State(); +} + +/*++ +COutPin::SetState +Description: +State setter for the output pin +--*/ + +DeviceStreamState COutPin::SetState(DeviceStreamState state) +{ + CAutoLock Lock(lock()); + DeviceStreamState oldState = m_state->State(); + m_state = m_states[state]; + return oldState; + +} + +/*++ +COutPin::FlushQueues +Description: +Called from the device Transform when the output queues have to be flushed + +--*/ +HRESULT COutPin::FlushQueues() +{ + HRESULT hr = S_OK; + CAutoLock Lock( lock() ); + + for ( DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++ ) + { + CPinQueue *que = m_queues[ dwIndex ]; + que->Clear(); + } + + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} +/*++ +COutPin::ChangeMediaTypeFromInpin +Description: +called from the Device Transfrom When the input media type is changed. This will result in +the xvp being possibly installed in the queue if the media types set on the input +and the output dont match +--*/ +HRESULT COutPin::ChangeMediaTypeFromInpin( + _In_ CInPin* inPin, + _In_ IMFMediaType *pInMediatype, + _In_ IMFMediaType* pOutMediaType, + _In_ DeviceStreamState state) +{ + HRESULT hr = S_OK; + CPinQueue *que = NULL; + CAutoLock Lock(lock()); + // + //Set the state to disabled and while going out we will reset the state back to the requested state + //Flush so that we drop any samples we have in store!! + // + SetState(DeviceStreamState_Disabled); + FlushQueues(); + + for (DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++) + { + que = m_queues[ dwIndex ]; + if (inPin->streamId() == que->pinStreamId()) + { + break; + } + que = NULL; + } + + if ( que ) + { + // + //recreate the tee, pass the D3D Manager to the Tee which will use DX if D3D manager is present + // + IUnknown *pD3DManagerUnk = NULL; + + (VOID)Parent()->GetD3DDeviceManager( &pD3DManagerUnk ); + hr = que->RecreateTee( pInMediatype, pOutMediaType, pD3DManagerUnk ); + if ( SUCCEEDED( hr ) ) + { + (VOID)setMediaType( pOutMediaType ); + (VOID)SetState( state ); + } + SAFE_RELEASE(pD3DManagerUnk); + } + return hr; +} + +/*++ +Description: + called from the IMFdeviceTransform's +--*/ + +STDMETHODIMP COutPin::GetOutputStreamInfo( + _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo + ) +{ + HRESULT hr = S_OK; + IMFMediaType* pMediatype = nullptr; + + getMediaType( &pMediatype ); + + if (SUCCEEDED(hr) && !pMediatype) { + pMediatype->Release(); + pStreamInfo->cbAlignment = 0; + pStreamInfo->cbSize = 0; + pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; + pStreamInfo->dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + //We provide our samples.. + } + else { + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + } + return hr; +} + +/*++ +COutPin::ProcessOutput +Description: + called from the Device Transfrom when the transform manager demands output samples.. + If we have samples we forward it. + If we are a photo pin then we forward only if trigger is sent. We ask the devicetransform if we have recieved the transform or not. + If we have recieved the sample and we are passing out a sample we should reset the trigger set on the Device Transform +--*/ + +STDMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags, + _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample, + _Out_ DWORD *pdwStatus + ) +{ + HRESULT hr = S_OK; + IMFSample* pSample = nullptr; + GUID pinClsid = GUID_NULL; + BOOL IsImagePin = FALSE; + BOOL IsSkipSample = FALSE; + UNREFERENCED_PARAMETER(pdwStatus); + UNREFERENCED_PARAMETER(dwFlags); + CAutoLock lock(lock()); + DMFTCHECKHR_GOTO(m_state->Open(), done); + + // + //Check if we are an image photo pin. The process output in that case should only proceed if trigger has been sent + //Candidate for subclass! + // + + if (SUCCEEDED(GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinClsid)) + && ((IsEqualCLSID(pinClsid, PINNAME_IMAGE)) || IsEqualCLSID(pinClsid, PINNAME_VIDEO_STILL))) + { + IsImagePin = TRUE; + } + + if (IsImagePin && !Parent()->isPhotoTriggerSent()) + { + IsSkipSample = TRUE; + } + + + + for ( DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++ ) + { + CPinQueue *que = m_queues[dwIndex]; + + pOutputSample->dwStatus = S_OK; + + if (!que->Remove(&pSample)) + { + break; + } + + MFTIME llTime = 0L; + + if (FAILED(pSample->GetSampleTime(&llTime))) + { + llTime = MFGetSystemTime(); + pSample->SetSampleTime(llTime); + } + + if (!IsSkipSample) + { + if (m_firstSample) + { + pSample->SetUINT32(MFSampleExtension_Discontinuity,TRUE); + SetFirstSample(FALSE); + } + + // + // Any processing before we pass the sample to further in the pipeline should be done here + // PROCESSSAMPLE(pSample); + // + + pOutputSample->pSample = pSample; + pOutputSample->dwStatus = S_OK; + } + else + { + SAFERELEASE(pSample); + } + } + if (!IsSkipSample && IsImagePin && pSample) + { + // + //A sample has been sent over so image pin should exit + // +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) + if (Parent()->IsPhotoConfirmationEnabled()) + { + // + // Photo confirmation is enabled i.e. the pipeline has set up photo confirmation + // Service photo confirmation. + // + ComPtr<IMFMediaType> spMediaType = nullptr; + + DMFTCHECKHR_GOTO(getMediaType(spMediaType.GetAddressOf()), done); + + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Calling PhotoConfirmation %p, is passed", pSample); + + DMFTCHECKHR_GOTO(Parent()->ProcessCapturePhotoConfirmationCallBack(spMediaType.Get(), pSample), done); + } +#endif + if (!Parent()->isPhotoModePhotoSequence()) + { + // + //A sample has been sent over so image pin should exit + // + Parent()->setPhotoTriggerSent(FALSE); + } + } +done: + return hr; +} + +/*++ + COutPin::KsProperty +Description: +The KsProperty for the Pin.. this is to reroute all pin kscontrols to the input pin +--*/ +STDMETHODIMP COutPin::KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned + ) +{ + // + //Route it to input pin + // + return m_spIkscontrol->KsProperty(pProperty, + ulPropertyLength, + pPropertyData, + ulDataLength, + pBytesReturned); +} + + + diff --git a/AVStream/sampledevicemft/basepin.h b/AVStream/sampledevicemft/basepin.h new file mode 100644 index 00000000..9b254e2a --- /dev/null +++ b/AVStream/sampledevicemft/basepin.h @@ -0,0 +1,596 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// +#pragma once +#include "stdafx.h" +#include "common.h" + + +extern DeviceStreamState pinStateTransition[][4]; + + +class CPinQueue; +class CPinState; +class CMultipinMft; + +class CBasePin: + public IMFAttributes, + public IKsControl +{ +public: + CBasePin( _In_ ULONG _id=0, _In_ CMultipinMft *parent=NULL); + + virtual ~CBasePin() = 0; + virtual STDMETHODIMP_(DeviceStreamState) GetState() = 0; + virtual STDMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState State) = 0; + + + // + //IUnknown Interface functions + // + + STDMETHODIMP_(ULONG) AddRef( + void + ) + { + return InterlockedIncrement(&m_nRefCount); + } + STDMETHODIMP_(ULONG) Release( + void + ) + { + ULONG uCount = InterlockedDecrement(&m_nRefCount); + if (uCount == 0) + { + delete this; + } + return uCount; + } + + STDMETHODIMP_(HRESULT) QueryInterface( + _In_ REFIID riid, + _Outptr_result_maybenull_ void **ppvObject + ); + // + // IKsControl Interface functions + // + + STDMETHOD(KsProperty)( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned + ) + { + if ( m_spIkscontrol!=nullptr ) + { + return m_spIkscontrol->KsProperty(pProperty, + ulPropertyLength, + pPropertyData, + ulDataLength, + pBytesReturned); + } + else + { + return E_NOTIMPL; + } + } + // + //NOOPs for this iteration.. + // + STDMETHOD(KsMethod)( + _In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod, + _In_ ULONG ulMethodLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pMethodData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned + ) + { + UNREFERENCED_PARAMETER(pBytesReturned); + UNREFERENCED_PARAMETER(ulDataLength); + UNREFERENCED_PARAMETER(pMethodData); + UNREFERENCED_PARAMETER(pMethod); + UNREFERENCED_PARAMETER(ulMethodLength); + return S_OK; + } + + STDMETHOD(KsEvent)( + _In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned + ) + { + UNREFERENCED_PARAMETER(pBytesReturned); + UNREFERENCED_PARAMETER(ulDataLength); + UNREFERENCED_PARAMETER(pEventData); + UNREFERENCED_PARAMETER(pEvent); + UNREFERENCED_PARAMETER(ulEventLength); + return S_OK; + } + + // + //IMFAttributes implementation + // + STDMETHOD(GetItem)( + _In_ REFGUID guidKey, + _Inout_opt_ PROPVARIANT* pValue + ) + { + return m_spAttributes->GetItem(guidKey, pValue); + } + + STDMETHOD(GetItemType)( + _In_ REFGUID guidKey, + _Out_ MF_ATTRIBUTE_TYPE* pType + ) + { + return m_spAttributes->GetItemType(guidKey, pType); + } + + STDMETHOD(CompareItem)( + _In_ REFGUID guidKey, + _In_ REFPROPVARIANT Value, + _Out_ BOOL* pbResult + ) + { + return m_spAttributes->CompareItem(guidKey, Value, pbResult); + } + + STDMETHOD(Compare)( + _In_ IMFAttributes* pTheirs, + _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType, + _Out_ BOOL* pbResult + ) + { + return m_spAttributes->Compare(pTheirs, MatchType, pbResult); + } + + STDMETHOD(GetUINT32)( + _In_ REFGUID guidKey, + _Out_ UINT32* punValue + ) + { + return m_spAttributes->GetUINT32(guidKey, punValue); + } + + STDMETHOD(GetUINT64)( + _In_ REFGUID guidKey, + _Out_ UINT64* punValue + ) + { + return m_spAttributes->GetUINT64(guidKey, punValue); + } + + STDMETHOD(GetDouble)( + _In_ REFGUID guidKey, + _Out_ double* pfValue + ) + { + return m_spAttributes->GetDouble(guidKey, pfValue); + } + + STDMETHOD(GetGUID)( + _In_ REFGUID guidKey, + _Out_ GUID* pguidValue + ) + { + return m_spAttributes->GetGUID(guidKey, pguidValue); + } + + STDMETHOD(GetStringLength)( + _In_ REFGUID guidKey, + _Out_ UINT32* pcchLength + ) + { + return m_spAttributes->GetStringLength(guidKey, pcchLength); + } + + STDMETHOD(GetString)( + _In_ REFGUID guidKey, + _Out_writes_(cchBufSize) LPWSTR pwszValue, + _In_ UINT32 cchBufSize, + _Inout_opt_ UINT32* pcchLength + ) + { + return m_spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength); + } + + STDMETHOD(GetAllocatedString)( + _In_ REFGUID guidKey, + _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue, + _Inout_ UINT32* pcchLength + ) + { + return m_spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength); + } + + STDMETHOD(GetBlobSize)( + _In_ REFGUID guidKey, + _Out_ UINT32* pcbBlobSize + ) + { + return m_spAttributes->GetBlobSize(guidKey, pcbBlobSize); + } + + STDMETHOD(GetBlob)( + _In_ REFGUID guidKey, + _Out_writes_(cbBufSize) UINT8* pBuf, + UINT32 cbBufSize, + _Inout_ UINT32* pcbBlobSize + ) + { + return m_spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize); + } + + STDMETHOD(GetAllocatedBlob)( + __RPC__in REFGUID guidKey, + __RPC__deref_out_ecount_full_opt(*pcbSize) UINT8** ppBuf, + __RPC__out UINT32* pcbSize + ) + { + return m_spAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize); + } + + STDMETHOD(GetUnknown)( + __RPC__in REFGUID guidKey, + __RPC__in REFIID riid, + __RPC__deref_out_opt LPVOID *ppv + ) + { + return m_spAttributes->GetUnknown(guidKey, riid, ppv); + } + + STDMETHOD(SetItem)( + _In_ REFGUID guidKey, + _In_ REFPROPVARIANT Value + ) + { + return m_spAttributes->SetItem(guidKey, Value); + } + + STDMETHOD(DeleteItem)( + _In_ REFGUID guidKey + ) + { + return m_spAttributes->DeleteItem(guidKey); + } + + STDMETHOD(DeleteAllItems)() + { + return m_spAttributes->DeleteAllItems(); + } + + STDMETHOD(SetUINT32)( + _In_ REFGUID guidKey, + _In_ UINT32 unValue + ) + { + return m_spAttributes->SetUINT32(guidKey, unValue); + } + + STDMETHOD(SetUINT64)( + _In_ REFGUID guidKey, + _In_ UINT64 unValue + ) + { + return m_spAttributes->SetUINT64(guidKey, unValue); + } + + STDMETHOD(SetDouble)( + _In_ REFGUID guidKey, + _In_ double fValue + ) + { + return m_spAttributes->SetDouble(guidKey, fValue); + } + + STDMETHOD(SetGUID)( + _In_ REFGUID guidKey, + _In_ REFGUID guidValue + ) + { + return m_spAttributes->SetGUID(guidKey, guidValue); + } + + STDMETHOD(SetString)( + _In_ REFGUID guidKey, + _In_ LPCWSTR wszValue + ) + { + return m_spAttributes->SetString(guidKey, wszValue); + } + + STDMETHOD(SetBlob)( + _In_ REFGUID guidKey, + _In_reads_(cbBufSize) const UINT8* pBuf, + UINT32 cbBufSize + ) + { + return m_spAttributes->SetBlob(guidKey, pBuf, cbBufSize); + } + + STDMETHOD(SetUnknown)( + _In_ REFGUID guidKey, + _In_ IUnknown* pUnknown + ) + { + return m_spAttributes->SetUnknown(guidKey, pUnknown); + } + + STDMETHOD(LockStore)() + { + return m_spAttributes->LockStore(); + } + + STDMETHOD(UnlockStore)() + { + return m_spAttributes->UnlockStore(); + } + + STDMETHOD(GetCount)( + _Out_ UINT32* pcItems + ) + { + return m_spAttributes->GetCount(pcItems); + } + + STDMETHOD(GetItemByIndex)( + UINT32 unIndex, + _Out_ GUID* pguidKey, + _Inout_ PROPVARIANT* pValue + ) + { + return m_spAttributes->GetItemByIndex(unIndex, pguidKey, pValue); + } + + STDMETHOD(CopyAllItems)( + _In_ IMFAttributes* pDest + ) + { + return m_spAttributes->CopyAllItems(pDest); + } + + // + //Helper Functions + // + __inline DWORD streamId() + { + return m_StreamId; + } + + __inline VOID setMediaType(_In_opt_ IMFMediaType *pMediaType) + { + m_setMediaType = pMediaType; + } + + __inline HRESULT getMediaType(_Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType) + { + HRESULT hr = S_OK; + if (!ppMediaType) + return E_INVALIDARG; + + if (m_setMediaType != nullptr) + { + hr = m_setMediaType.CopyTo(ppMediaType); + } + else + { + hr = MF_E_TRANSFORM_TYPE_NOT_SET; + } + return hr; + } + + __inline STDMETHOD (getPinAttributes) (_In_ IMFAttributes **ppAttributes) + { + HRESULT hr = S_OK; + DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG ); + DMFTCHECKHR_GOTO ( QueryInterface( IID_PPV_ARGS(ppAttributes) ), done ); + done: + return hr; + } + + STDMETHODIMP AddMediaType( + _Inout_ DWORD *pos, + _In_ IMFMediaType *pMediatype); /*Filling the media types data structure*/ + STDMETHODIMP GetMediaTypeAt( + _In_ DWORD pos, + _Outptr_result_maybenull_ IMFMediaType **pMediaType); /* getting the data from the data structure*/ + STDMETHODIMP_(BOOL) IsMediaTypeSupported( + _In_ IMFMediaType *pMediaType, + _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_) + IMFMediaType **ppIMFMediaTypeFull); + STDMETHODIMP GetOutputAvailableType( + _In_ DWORD dwTypeIndex, + _Out_opt_ IMFMediaType **ppType); + +protected: + // + //Inline helper functions + // + _inline CMultipinMft* Parent() + { + return m_Parent.Get(); + } + __inline HRESULT setAttributes(_In_ IMFAttributes* _pAttributes) + { + m_spAttributes = _pAttributes; + return S_OK; + } + __inline CCritSec& lock() + { + return m_lock; + } + IMFMediaTypeArray m_listOfMediaTypes; + ComPtr<IMFAttributes> m_spAttributes; + ComPtr<IKsControl> m_spIkscontrol; + +private: + ULONG m_StreamId; /*Device Stream Id*/ + CCritSec m_lock; /*This is only used to change the reference count i.e. active users of this stream*/ + ComPtr<IMFMediaType> m_setMediaType; + ComPtr<CMultipinMft> m_Parent; + ULONG m_nRefCount; +}; + + + +class CInPin: public CBasePin{ +public: + CInPin( _In_opt_ IMFAttributes*, _In_ ULONG ulPinId = 0, _In_ CMultipinMft *pParent=NULL); + ~CInPin(); + + STDMETHOD ( Init )( + _In_ IMFTransform * + ); + STDMETHOD_( VOID, ConnectPin)( + _In_ CBasePin * + ); + STDMETHOD (SendSample)( + _In_ IMFSample * + ); + STDMETHODIMP GenerateMFMediaTypeListFromDevice( + _In_ UINT uiStreamId + ); + STDMETHODIMP WaitForSetInputPinMediaChange( + ); + STDMETHOD_ (DeviceStreamState, SetState)( + _In_ DeviceStreamState + ); /*True for Active and False for Stop*/ + STDMETHOD_(DeviceStreamState, GetState)( + VOID + ); + // + //Corresponding IMFDeviceTransform functions for the Pin + // + STDMETHODIMP_(HRESULT) GetInputStreamPreferredState( + _Inout_ DeviceStreamState *value, + _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType + ); + STDMETHODIMP_(HRESULT) SetInputStreamState( + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags + ); + + // + //Inline functions + // + __inline IMFMediaType* getPreferredMediaType() + { + return m_prefferedMediaType.Get(); + } + __inline VOID setPreferredMediaType( _In_ IMFMediaType *pMediaType) + { + m_prefferedMediaType = pMediaType; + } + __inline DeviceStreamState setPreferredStreamState(_In_ DeviceStreamState streamState) + { + return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_preferredStreamState, (LONG)streamState, (LONG)m_preferredStreamState); + } + __inline DeviceStreamState getPreferredStreamState() + { + return m_preferredStreamState; + } + +protected: + ComPtr<IMFTransform> m_spSourceTransform; /*Source Transform*/ +private: + GUID m_stStreamType; /*GUID representing the GUID*/ + ULONG m_activeStreamCount; /*Set when this stream is active*/ + vector<CBasePin*> m_outpins; + DeviceStreamState m_state; + DeviceStreamState m_preferredStreamState; + ComPtr<IMFMediaType> m_prefferedMediaType; + HANDLE m_waitInputMediaTypeWaiter; /*Set when the input media type is changed*/ +}; + + + +class COutPin: public CBasePin{ +public: + COutPin( _In_ ULONG id = 0, + _In_opt_ CMultipinMft *pparent = NULL, + _In_ IKsControl* iksControl=NULL); + ~COutPin(); + STDMETHODIMP AddPin( + _In_ DWORD pinId + ); + STDMETHODIMP AddSample( + _In_ IMFSample *pSample, + _In_ CBasePin *inPin + ); + STDMETHODIMP AddSampleInternal( + _In_ IMFSample *pSample, + _In_ CBasePin *inPin + ); + STDMETHODIMP RemoveSample( + _Out_ IMFSample ** + ); + STDMETHODIMP_(DeviceStreamState) SetState( + _In_ DeviceStreamState + ); /*True for Active and False for Stop*/ + STDMETHODIMP_(DeviceStreamState) GetState( + ); + STDMETHODIMP FlushQueues( + ); + STDMETHODIMP GetOutputStreamInfo( + _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo + ); + STDMETHODIMP ChangeMediaTypeFromInpin( + _In_ CInPin* inPin, + _In_ IMFMediaType *pInMediatype, + _In_ IMFMediaType* pOutMediaType, + _In_ DeviceStreamState state ); + STDMETHODIMP ProcessOutput ( + _In_ DWORD dwFlags, + _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample, + _Out_ DWORD *pdwStatus + ); + STDMETHODIMP KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned + ); + STDMETHODIMP_(VOID) SetD3Dmanager( + _In_opt_ IUnknown * + ); + STDMETHODIMP_(VOID) SetFirstSample( + _In_ BOOL + ); + + +private: + vector< CPinState *> m_states; /*Array of possible states*/ + CPinState* m_state; /*Current state*/ + vector< CPinQueue *> m_queues; /*List of Queues corresponding to input pins*/ + BOOL m_firstSample; + friend class CPinState; +}; + +// +//Not Implemented!!! +// + +class CImagePin : public COutPin{ +private: + BOOL isTriggerSent; +public: + CImagePin(); + ~CImagePin(); + STDMETHODIMP ProcessOutput( + _In_ DWORD dwFlags, + _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample, + _Out_ DWORD *pdwStatus + ); +}; + + diff --git a/AVStream/sampledevicemft/common.h b/AVStream/sampledevicemft/common.h new file mode 100644 index 00000000..238decfb --- /dev/null +++ b/AVStream/sampledevicemft/common.h @@ -0,0 +1,717 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#pragma once + +#define GUID_STRING_LENGTH 36 +#define GUID_BUFFER_SIZE 37 +#define SLEEP_5MILLISEC 5 +#define SLEEP_ONE_SECOND 1000 // One second in milli seconds. + +#ifndef MF_WPP +#define DMFTRACE(...) +#endif + +//TP_NORMAL +//TP_LOWEST +//TP_LOW +//TP_HIGH +//TP_HIGHEST +//TP_ERROR +//TP_MUTED = 0x00070000 + + + +#define mf_assert(a) if(!a) DebugBreak() + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(CtlGUID_DMFTTrace, (CBCCA12E, 9472, 409D, A1B1, 753C98BF03C0), \ + WPP_DEFINE_BIT(DMFT_INIT) \ + WPP_DEFINE_BIT(DMFT_CONTROL) \ + WPP_DEFINE_BIT(DMFT_GENERAL) \ + ) + +#define WPP_LEVEL_FLAG_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAG_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) +#define WPP_FLAG_LEVEL_LOGGER(flags,lvl) WPP_LEVEL_LOGGER(flags) +#define WPP_FLAG_LEVEL_ENABLED(flags, lvl) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +#define SAFE_ADDREF(p) if( NULL != p ) { ( p )->AddRef(); } +#define SAFE_DELETE(p) delete p; p = NULL; +#define SAFE_SHUTDELETE(p) if( NULL != p ) { ( p )->Shutdown(); delete p; p = NULL; } +#define SAFE_RELEASE(p) if( NULL != p ) { ( p )->Release(); p = NULL; } +#define SAFE_SHUTRELEASE(p) if( NULL != p ) { ( p )->Shutdown(); ( p )->Release(); p = NULL; } +#define SAFE_CLOSERELEASE(p) if( NULL != p ) { ( p )->Close( TRUE ); ( p )->Release(); p = NULL; } +#define SAFE_COTASKMEMFREE(p) CoTaskMemFree( p ); p = NULL; +#define SAFE_SYSFREESTRING(p) SysFreeString( p ); p = NULL; +#define SAFE_ARRAYDELETE(p) delete [] p; p = NULL; +#define SAFE_BYTEARRAYDELETE(p) delete [] (BYTE*) p; p = NULL; + + + +#define DMFTCHECKHR_GOTO(val,label) \ + hr = (val); \ +if (FAILED(hr)) {\ + /*DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); */\ + goto label; \ +} + + +#define DMFTCHECKNULL_GOTO( val, label, err) \ +if( (val) == NULL ) { \ + hr = (err); \ + /*DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);*/\ + goto label; \ +} + +#define TP_SCOPE_TRACE TP_NORMAL +#define DH_THIS_FILE DH_DEVPROXY + +#define SAFERELEASE(x) \ +if (x) {\ + x->Release(); \ + x = NULL; \ +} + +#define CHK_LOG_BRK(exp) \ +if (FAILED(hr = (exp))) {\ + wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \ + /*MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MULTIPINERROR File: %s Ln:%d",__FILE__,__LINE__);*/\ + break; \ +} + + +#define CHK_NULL_BRK(exp) \ +if ((exp) == NULL) {\ +hr = E_OUTOFMEMORY; \ +wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \ +break; \ +} + +#define CHK_NULL_PTR_BRK(exp) \ +if ((exp) == NULL) {\ +hr = E_INVALIDARG; \ +wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \ +break; \ +} + +#define CHK_BOOL_BRK(exp) \ +if (!exp) {\ + hr = E_FAIL; \ + wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \ + break; \ +} + + +// +// The Below type definitions are added for this iteration. It will taken out in the +// next one when we will have the windows headers modified to include the interfaces +// externally. +// + + +#if !defined(_IKsControl_) +#define _IKsControl_ +interface DECLSPEC_UUID("28F54685-06FD-11D2-B27A-00A0C9223196") IKsControl; +#undef INTERFACE +#define INTERFACE IKsControl +DECLARE_INTERFACE_(IKsControl, IUnknown) +{ + STDMETHOD(KsProperty)( + THIS_ + IN PKSPROPERTY Property, + IN ULONG PropertyLength, + IN OUT LPVOID PropertyData, + IN ULONG DataLength, + OUT ULONG* BytesReturned + ) PURE; + STDMETHOD(KsMethod)( + THIS_ + IN PKSMETHOD Method, + IN ULONG MethodLength, + IN OUT LPVOID MethodData, + IN ULONG DataLength, + OUT ULONG* BytesReturned + ) PURE; + STDMETHOD(KsEvent)( + THIS_ + IN PKSEVENT Event OPTIONAL, + IN ULONG EventLength, + IN OUT LPVOID EventData, + IN ULONG DataLength, + OUT ULONG* BytesReturned + ) PURE; +}; +#endif //!defined(_IKsControl_) + + + +#if !defined(__IMFDeviceTransform_INTERFACE_DEFINED__) +// +//These definitions will have to be taken out when the +//internal defines are made public +// + +EXTERN_GUID(MEDeviceStreamCreated, 0x0252a1cf, 0x3540, 0x43b4, 0x91, 0x64, 0xd7, 0x2e, 0xb4, 0x05, 0xfa, 0x40); + +typedef +enum _DeviceStreamState +{ + DeviceStreamState_Stop = 0, + DeviceStreamState_Pause = (DeviceStreamState_Stop + 1), + DeviceStreamState_Run = (DeviceStreamState_Pause + 1), + DeviceStreamState_Disabled = (DeviceStreamState_Run + 1) +} DeviceStreamState; + +/* size is 4, align is 4*/ +typedef enum _DeviceStreamState *PDeviceStreamState; + +EXTERN_C const IID IID_IMFDeviceTransform; +MIDL_INTERFACE("D818FBD8-FC46-42F2-87AC-1EA2D1F9BF32") +IMFDeviceTransform : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE InitializeTransform( + /* [annotation][in] */ + _In_ IMFAttributes *pAttributes) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInputAvailableType( + /* [annotation][in] */ + _In_ DWORD dwInputStreamID, + /* [annotation][in] */ + _In_ DWORD dwTypeIndex, + /* [annotation][out] */ + _COM_Outptr_ IMFMediaType **pMediaType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInputCurrentType( + /* [annotation][in] */ + _In_ DWORD dwInputStreamID, + /* [annotation][out] */ + _COM_Outptr_ IMFMediaType **pMediaType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInputStreamAttributes( + /* [annotation][in] */ + _In_ DWORD dwInputStreamID, + /* [annotation][out] */ + _COM_Outptr_ IMFAttributes **ppAttributes) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetOutputAvailableType( + /* [annotation][in] */ + _In_ DWORD dwOutputStreamID, + /* [annotation][in] */ + _In_ DWORD dwTypeIndex, + /* [annotation][out] */ + _COM_Outptr_ IMFMediaType **pMediaType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetOutputCurrentType( + /* [annotation][in] */ + _In_ DWORD dwOutputStreamID, + /* [annotation][out] */ + _COM_Outptr_ IMFMediaType **pMediaType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetOutputStreamAttributes( + /* [annotation][in] */ + _In_ DWORD dwOutputStreamID, + /* [annotation][out] */ + _COM_Outptr_ IMFAttributes **ppAttributes) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetStreamCount( + /* [annotation][out] */ + _Out_ DWORD *pcInputStreams, + /* [annotation][out] */ + _Out_ DWORD *pcOutputStreams) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetStreamIDs( + /* [annotation][in] */ + _In_ DWORD dwInputIDArraySize, + /* [annotation][out] */ + _Out_ DWORD *pdwInputStreamIds, + /* [annotation][in] */ + _In_ DWORD dwOutputIDArraySize, + /* [annotation][out] */ + _Out_ DWORD *pdwOutputStreamIds) = 0; + + virtual HRESULT STDMETHODCALLTYPE ProcessEvent( + /* [annotation][in] */ + _In_ DWORD dwInputStreamID, + /* [annotation][in] */ + _In_ IMFMediaEvent *pEvent) = 0; + + virtual HRESULT STDMETHODCALLTYPE ProcessInput( + /* [annotation][in] */ + _In_ DWORD dwInputStreamID, + /* [annotation][in] */ + _In_ IMFSample *pSample, + /* [annotation][in] */ + _In_ DWORD dwFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE ProcessMessage( + /* [annotation][in] */ + _In_ MFT_MESSAGE_TYPE eMessage, + /* [annotation][in] */ + _In_ ULONG_PTR ulParam) = 0; + + virtual HRESULT STDMETHODCALLTYPE ProcessOutput( + /* [annotation][in] */ + _In_ DWORD dwFlags, + /* [annotation][in] */ + _In_ DWORD cOutputBufferCount, + /* [size_is][annotation][out][in] */ + _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample, + /* [annotation][out] */ + _Out_ DWORD *pdwStatus) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetInputStreamState( + /* [annotation][in] */ + _In_ DWORD dwStreamID, + /* [annotation][in] */ + _In_ IMFMediaType *pMediaType, + /* [annotation][in] */ + _In_ DeviceStreamState value, + /* [annotation][in] */ + _In_ DWORD dwFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInputStreamState( + /* [annotation][in] */ + _In_ DWORD dwStreamID, + /* [annotation][out] */ + _Out_ DeviceStreamState *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetOutputStreamState( + /* [annotation][in] */ + _In_ DWORD dwStreamID, + /* [annotation][in] */ + _In_ IMFMediaType *pMediaType, + /* [annotation][in] */ + _In_ DeviceStreamState value, + /* [annotation][in] */ + _In_ DWORD dwFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetOutputStreamState( + /* [annotation][in] */ + _In_ DWORD dwStreamID, + /* [annotation][out] */ + _Out_ DeviceStreamState *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInputStreamPreferredState( + /* [annotation][in] */ + _In_ DWORD dwStreamID, + /* [annotation][out] */ + _Out_ DeviceStreamState *value, + /* [annotation][out] */ + _COM_Outptr_ IMFMediaType **ppMediaType) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushInputStream( + /* [annotation][in] */ + _In_ DWORD dwStreamIndex, + /* [annotation][in] */ + _In_ DWORD dwFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushOutputStream( + /* [annotation][in] */ + _In_ DWORD dwStreamIndex, + /* [annotation][in] */ + _In_ DWORD dwFlags) = 0; + +}; + +#endif + + +interface IDirect3DDeviceManager9; +//Forward defintion +class CBasePin; +////////////////////////////////////////////////////////////////////////// +// CCritSec +// Description: Wraps a critical section. +////////////////////////////////////////////////////////////////////////// + +class CCritSec +{ +private: + CRITICAL_SECTION m_criticalSection; +public: + CCritSec(); + ~CCritSec(); + _Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection) + void Lock(); + _Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection) + void Unlock(); +}; + + +////////////////////////////////////////////////////////////////////////// +// CAutoLock +// Description: Provides automatic locking and unlocking of a +// of a critical section. +////////////////////////////////////////////////////////////////////////// + +class CAutoLock +{ +protected: + CCritSec *m_pCriticalSection; +public: + _Acquires_lock_(this->m_pCriticalSection->m_criticalSection) + CAutoLock(CCritSec& crit); + _Acquires_lock_(this->m_pCriticalSection->m_criticalSection) + CAutoLock(CCritSec* crit); + _Releases_lock_(this->m_pCriticalSection->m_criticalSection) + ~CAutoLock(); +}; + +////////////////////////////////////////////////////////////////////////// +// CMediaTypePrinter +// Description: Rudimentary class for printing media type! +////////////////////////////////////////////////////////////////////////// + +#define MEDIAPRINTER_STARTLEN (512) + +class CMediaTypePrinter{ +private: + IMFMediaType *pMediaType; + PCHAR m_pBuffer; + ULONG buffLen; +public: + CMediaTypePrinter( _In_ IMFMediaType *_pMediaType ); + ~CMediaTypePrinter( ); + STDMETHODIMP_(PCHAR) ToCompleteString( ); + STDMETHODIMP_(PCHAR) ToString(); +}; + + +// +//The below guid is used to register the GUID as the Device Transform. This should be adeed to the +//HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses\ and under the +//GLOBAL#\Device Parameters key, add a CameraDeviceMFTCLSID value, and set its value to +// {0E313280-3169-4F41-A329-9E854169634F} for the Pipeline to pick up the Transform. +// +DEFINE_GUID(CLSID_MultiPinMFT, + 0xe313280, 0x3169, 0x4f41, 0xa3, 0x29, 0x9e, 0x85, 0x41, 0x69, 0x63, 0x4f); + + +typedef enum _MF_TRANSFORM_XVP_OPERATION{ + DeviceMftTransformXVPDisruptiveIn, //Break the XVP tranform and go to the new Media Type + DeviceMftTransformXVPDisruptiveOut, //Keep the old transform + DeviceMftTransformXVPCurrent, //Don't need an XVP + DeviceMftTransformXVPIllegal //Either of the media types NULL, Major types don't match +}MF_TRANSFORM_XVP_OPERATION,*PMF_TRANSFORM_XVP_OPERATION; + +typedef std::vector< IMFMediaType *> IMFMediaTypeArray; +typedef std::vector< CBasePin *> CBasePinArray; +typedef std::vector< IMFSample *> IMFSampleList; +typedef std::pair< std::multimap<int, int>::iterator, std::multimap<int, int>::iterator > MMFTMMAPITERATOR; + + +HRESULT CreateCodec( + _In_opt_ IMFMediaType * inMediaType, + _In_opt_ IMFMediaType *outMediaType, + _In_ BOOL operation /*True = Encode, False = Decode*/, + _Out_ IMFTransform **pTransform + ); + +STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair( + _In_ IMFMediaType *inMediaType, + _In_ IMFMediaType *outMediaType, + _Out_ bool *optimized, + _Out_ bool *optimizedxvpneeded + ); + +STDMETHODIMP CompareMediaTypesForXVP(_In_opt_ IMFMediaType *inMediaType, + _In_ IMFMediaType *newMediaType, + _Inout_ MF_TRANSFORM_XVP_OPERATION *operation + ); + +STDMETHODIMP RandomnizeMediaTypes( + _In_ IMFMediaTypeArray &pMediaTypeArray + ); + +STDMETHODIMP IsInputDxSample( + _In_ IMFSample* pSample, + _Inout_ BOOL *isDxSample + ); + +STDMETHODIMP_(BOOL) IsPinStateInActive( + _In_ DeviceStreamState state + ); + +STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType( + _In_ GUID guidSubType + ); +LPSTR DumpGUIDA( + _In_ REFGUID guid + ); + + +void printMessageEvent(MFT_MESSAGE_TYPE msg); + + +template <typename Lambda> +HRESULT ExceptionBoundary(Lambda&& lambda) +{ + try + { + lambda(); + return S_OK; + } + catch (const _com_error& e) + { + return e.Error(); + } + catch (const std::bad_alloc&) + { + return E_OUTOFMEMORY; + } + catch (const std::out_of_range&) + { + return MF_E_INVALIDINDEX; + } + catch (...) + { + return E_FAIL; + } +} + + +// +// Custom Pin GUID. The avstream driver should define a PIN_DESCRIPTOR with this GUID +// defined in cateogory. This will lead to devproxy creating this pin. This pin however +// cannot be used by the pipeline as it may share a custom media type and pipeline could +// fail. Moreover pipeline can currently (when this sample is written) only deal with +// the known pins (PREVIEW/CAPTURE/IMAGE). This code snippet creates a custom pin +// and +// +DEFINE_GUID(AVSTREAM_CUSTOM_PIN_IMAGE, + 0x888c4105, 0xb328, 0x4ed6, 0xa3, 0xca, 0x2f, 0xf4, 0xc0, 0x3a, 0x9f, 0x33); + + +// +// The Below redirections are to support MFT0. Implement this only if you need to load +// MFT0 and DeviceMft simultaneously. +// + +#define _DEFINE_DEVICEMFT_MFT0HELPER_IMPL__ \ + STDMETHOD(MFTGetStreamLimits)( \ + _Inout_ DWORD *pdwInputMinimum, \ + _Inout_ DWORD *pdwInputMaximum, \ + _Inout_ DWORD *pdwOutputMinimum, \ + _Inout_ DWORD *pdwOutputMaximum \ + ) \ +{ \ + UNREFERENCED_PARAMETER(pdwInputMinimum); \ + UNREFERENCED_PARAMETER(pdwInputMaximum); \ + UNREFERENCED_PARAMETER(pdwOutputMinimum); \ + UNREFERENCED_PARAMETER(pdwOutputMaximum); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTGetStreamCount)( \ + _Inout_ DWORD* pdwInputStreams, \ + _Inout_ DWORD* pdwOutputStreams \ + ) \ +{ \ + return GetStreamCount(pdwInputStreams, pdwOutputStreams); \ +} \ + STDMETHOD(MFTGetStreamIDs)( \ + _In_ DWORD dwInputIDArraySize, \ + _Inout_updates_(dwInputIDArraySize) DWORD* pdwInputIDs, \ + _In_ DWORD dwOutputIDArraySize, \ + _Inout_updates_(dwOutputIDArraySize) DWORD* pdwOutputIDs \ + ) \ +{ \ + return GetStreamIDs(dwInputIDArraySize, \ + pdwInputIDs, \ + dwOutputIDArraySize, \ + pdwOutputIDs); \ +} \ + STDMETHOD(MFTGetInputStreamInfo)( \ + _In_ DWORD dwInputStreamID, \ + _Inout_ MFT_INPUT_STREAM_INFO* pStreamInfo \ + ) \ +{ \ + UNREFERENCED_PARAMETER(dwInputStreamID); \ + UNREFERENCED_PARAMETER(pStreamInfo); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTGetOutputStreamInfo)( \ + _In_ DWORD dwOutputStreamID, \ + _Inout_ MFT_OUTPUT_STREAM_INFO* pStreamInfo \ + ) \ +{ \ + UNREFERENCED_PARAMETER(dwOutputStreamID); \ + UNREFERENCED_PARAMETER(pStreamInfo); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTGetInputStreamAttributes)( \ + _In_ DWORD dwInputStreamID, \ + _Out_ IMFAttributes** ppAttributes \ + ) \ +{ \ + return GetInputStreamAttributes( \ + dwInputStreamID, \ + ppAttributes); \ +} \ + STDMETHOD(MFTGetOutputStreamAttributes)( \ + _In_ DWORD dwOutputStreamID, \ + _Out_ IMFAttributes** ppAttributes \ + ) \ +{ \ + return GetOutputStreamAttributes( \ + dwOutputStreamID, ppAttributes); \ +} \ + STDMETHOD(MFTDeleteInputStream)( \ + _In_ DWORD dwStreamID \ + ) \ +{ \ + UNREFERENCED_PARAMETER(dwStreamID); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTAddInputStreams)( \ + _In_ DWORD cStreams, \ + _In_ DWORD* adwStreamIDs \ + ) \ +{ \ + UNREFERENCED_PARAMETER(cStreams); \ + UNREFERENCED_PARAMETER(adwStreamIDs); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTGetInputAvailableType)( \ + _In_ DWORD dwInputStreamID, \ + _In_ DWORD dwTypeIndex, \ + _Out_ IMFMediaType** ppType \ + ) \ +{ \ + return GetInputAvailableType( \ + dwInputStreamID, dwTypeIndex, ppType); \ +} \ + STDMETHOD(MFTGetOutputAvailableType)( \ + _In_ DWORD dwOutputStreamID, \ + _In_ DWORD dwTypeIndex, \ + _Out_ IMFMediaType** ppMediaType \ + ) \ +{ \ + return GetOutputAvailableType( \ + dwOutputStreamID, dwTypeIndex, ppMediaType); \ +} \ + STDMETHOD(MFTSetInputType)( \ + _In_ DWORD dwInputStreamID, \ + _In_ IMFMediaType* pMediaType, \ + _In_ DWORD dwFlags \ + ) \ +{\ + UNREFERENCED_PARAMETER(dwInputStreamID); \ + UNREFERENCED_PARAMETER(pMediaType); \ + UNREFERENCED_PARAMETER(dwFlags); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTSetOutputType)( \ + _In_ DWORD dwOutputStreamID, \ + _In_ IMFMediaType* pMediaType, \ + _In_ DWORD dwFlags \ + ) \ +{ \ + UNREFERENCED_PARAMETER(dwOutputStreamID); \ + UNREFERENCED_PARAMETER(pMediaType); \ + UNREFERENCED_PARAMETER(dwFlags); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTGetInputCurrentType)( \ + _In_ DWORD dwInputStreamID, \ + _Out_ IMFMediaType** ppMediaType \ + ) \ +{\ + UNREFERENCED_PARAMETER(dwInputStreamID); \ + UNREFERENCED_PARAMETER(ppMediaType); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTGetOutputCurrentType)( \ + _In_ DWORD dwOutputStreamID, \ + _Out_ IMFMediaType** ppMediaType \ + ) \ +{ \ + return GetOutputCurrentType(dwOutputStreamID, ppMediaType); \ +} \ + STDMETHOD(MFTGetInputStatus)( \ + _In_ DWORD dwInputStreamID, \ + _Inout_ DWORD* pdwFlags \ + )\ +{\ + UNREFERENCED_PARAMETER(dwInputStreamID); \ + UNREFERENCED_PARAMETER(pdwFlags); \ + return E_NOTIMPL; \ +}\ + STDMETHOD(MFTGetOutputStatus)( \ + _Inout_ DWORD *pdwFlags \ + ) \ +{ \ + UNREFERENCED_PARAMETER(pdwFlags); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTSetOutputBounds)( \ + _In_ LONGLONG hnsLowerBound, \ + _In_ LONGLONG hnsUpperBound \ + ) \ +{\ + UNREFERENCED_PARAMETER(hnsLowerBound); \ + UNREFERENCED_PARAMETER(hnsUpperBound); \ + return E_NOTIMPL; \ +}\ + STDMETHOD(MFTProcessMessage)( \ + _In_ MFT_MESSAGE_TYPE eMessage, \ + _In_ ULONG_PTR ulParam \ + ) \ +{ \ + UNREFERENCED_PARAMETER(eMessage); \ + UNREFERENCED_PARAMETER(ulParam); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTProcessInput)( \ + _In_ DWORD dwInputStreamID, \ + _In_ IMFSample* pSample, \ + _In_ DWORD dwFlags \ + ) \ +{ \ + UNREFERENCED_PARAMETER(dwInputStreamID); \ + UNREFERENCED_PARAMETER(pSample); \ + UNREFERENCED_PARAMETER(dwFlags); \ + return E_NOTIMPL; \ +} \ + STDMETHOD(MFTProcessOutput)( \ + _In_ DWORD dwFlags, \ + _In_ DWORD cOutputBufferCount, \ + _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, \ + _Inout_ DWORD *pdwStatus \ + ) \ +{ \ + UNREFERENCED_PARAMETER(dwFlags); \ + UNREFERENCED_PARAMETER(cOutputBufferCount); \ + UNREFERENCED_PARAMETER(pOutputSamples); \ + UNREFERENCED_PARAMETER(pdwStatus); \ + return E_NOTIMPL; \ +} + +// +// Object LifeTime manager. The Class has a global variable which +// maintains a reference count of the number of objects in the +// system managed by the DLL. +// +class CDMFTModuleLifeTimeManager{ +public: + CDMFTModuleLifeTimeManager() + { + InterlockedIncrement(&s_lObjectCount); + } + ~CDMFTModuleLifeTimeManager() + { + InterlockedDecrement(&s_lObjectCount); + } + static long GetDMFTObjCount() + { + return s_lObjectCount; + } +private: + static volatile long s_lObjectCount; +}; diff --git a/AVStream/sampledevicemft/custompin.cpp b/AVStream/sampledevicemft/custompin.cpp new file mode 100644 index 00000000..00edb329 --- /dev/null +++ b/AVStream/sampledevicemft/custompin.cpp @@ -0,0 +1,98 @@ +#include "stdafx.h" +#include "multipinmft.h" +#include "basepin.h" +#include "custompin.h" +#ifdef MF_WPP +#include "custompin.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif + + +// +// Implementation notes +// Implement this file only if you have custom media pins streaming +// This implementation just streams from the driver and sends it back +// to the pipeline. This method can be used to stream 3A/Statistic Pins. +// + +CCustomPin::CCustomPin( + _In_ IMFAttributes *pAttributes, + _In_ ULONG PinId, + _In_ CMultipinMft *pParent + ) + :CInPin( pAttributes, PinId, pParent ) +{ + +} +// +// Process input calls the pin here.. In this code sample we +// don't send it anywhere. It is simply shortcircuited back to the pipeline +// +STDMETHODIMP CCustomPin::SendSample( + _In_ IMFSample *pSample + ) +{ + // + // Log sample and exit.. The pipeline will just keep on churning more samples till + // We go into the stop state + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin %d recieved Sample %p", streamId(), pSample); + + return S_OK; +} + +// +// State change transitions on the custom pins are different than the other pins +// The other known pins i.e. preview, record, image etc are exposed out to the pipeline +// and the pipeline will set state on it, reset state, For the other pins we tell the +// pipeline that we have samples and the pipeline picks it up. +// +// The CUSTOM pin differs in that it's state has to be managed to by the device MFT. +// This code snippet just varies state transitions on the custom pin when the Device MFT +// changes state to STREAMING/END_STREAMING on it's exposed pins. +// +// The below function tells the pipeline to change the state on the custom pin by sending +// METransformInputStreamStateChanged event with the streamid attribute. The pipeline will +// call back in the custom pin at getprefferedmediatype and finally setinputstreamstate +// which will signal back here singnalling sucessful state transition. +// + +STDMETHODIMP_(DeviceStreamState) CCustomPin::SetState( + _In_ DeviceStreamState State + ) +{ + HRESULT hr = S_OK; + + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Id:%d Transition into state: %d ", streamId(), State); + + DeviceStreamState oldState = setPreferredStreamState( State ); + + if ( oldState != State ) + { + ComPtr<IMFMediaType> preferredMediaType = nullptr; + + if (State == DeviceStreamState_Run) + { + GetMediaTypeAt(0, preferredMediaType.ReleaseAndGetAddressOf()); + } + + setPreferredMediaType(preferredMediaType.Get()); + setPreferredStreamState( State ); + + { + // + // Notify the device transform manager that we have changed state + // + ComPtr<IMFMediaEvent> pEvent = nullptr; + DMFTCHECKHR_GOTO( MFCreateMediaEvent(METransformInputStreamStateChanged, GUID_NULL, S_OK, NULL, pEvent.ReleaseAndGetAddressOf()), done ); + DMFTCHECKHR_GOTO( pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, streamId()), done ); + DMFTCHECKHR_GOTO( Parent()->QueueEvent(pEvent.Get()), done ); + } + // + // Wait to be notified back from the pipeline. + // + DMFTCHECKHR_GOTO( WaitForSetInputPinMediaChange(),done ); + } +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return oldState; +} diff --git a/AVStream/sampledevicemft/custompin.h b/AVStream/sampledevicemft/custompin.h new file mode 100644 index 00000000..c0c3c35f --- /dev/null +++ b/AVStream/sampledevicemft/custompin.h @@ -0,0 +1,30 @@ +#pragma once +#include "stdafx.h" +#include "common.h" + +// +// Custom Pin is only an input pin in this sample..It is short circuited back +// to the pipeline. This can have uses in implementing depth pins etc. +// It is not exposed to the down stream i.e. captureengine or the +// WinRT code. +// +class CCustomPin : public CInPin{ +public: + + CCustomPin( + _In_ IMFAttributes *pAttributes, + _In_ ULONG PinId, + _In_ CMultipinMft *pParent + ); + STDMETHODIMP SendSample( + _In_ IMFSample *pSample + ); + STDMETHODIMP_( DeviceStreamState )SetState( + _In_ DeviceStreamState + ); +}; + +STDMETHODIMP CheckCustomPin( + _In_ CInPin * pin, + _Inout_ PBOOL isCustom + ); diff --git a/AVStream/sampledevicemft/dllmain.cpp b/AVStream/sampledevicemft/dllmain.cpp new file mode 100644 index 00000000..6978a9d5 --- /dev/null +++ b/AVStream/sampledevicemft/dllmain.cpp @@ -0,0 +1,354 @@ +////////////////////////////////////////////////////////////////////////// +// +// dllmain.cpp : Implements DLL exports and COM class factory +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Note: This source file implements the class factory for the transform, +// plus the following DLL functions: +// - DllMain +// - DllCanUnloadNow +// - DllRegisterServer +// - DllUnregisterServer +// - DllGetClassObject +// +////////////////////////////////////////////////////////////////////////// +#include "stdafx.h" +#include "common.h" +#include "multipinmft.h" +#include <initguid.h> + +#ifdef MF_WPP +#include "dllmain.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif + +// +// The static variable needed to check the object count of the deviceMFts loaded. +// + +volatile long CDMFTModuleLifeTimeManager::s_lObjectCount = 0; + + + +HRESULT RegisterObject(HMODULE hModule, REFGUID guid, PCWSTR pszDescription, PCWSTR pszThreadingModel); + +HRESULT UnregisterObject(const GUID& guid); + + +// Module Ref count +long g_cRefModule = 0; + +// Handle to the DLL's module +HMODULE g_hModule = NULL; + +void DllAddRef() +{ + InterlockedIncrement(&g_cRefModule); +} + +void DllRelease() +{ + InterlockedDecrement(&g_cRefModule); +} + +// +// IClassFactory implementation +// + +typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject); +struct CLASS_OBJECT_INIT +{ + const CLSID *pClsid; + PFNCREATEINSTANCE pfnCreate; +}; + +// Classes supported by this module: +const CLASS_OBJECT_INIT c_rgClassObjectInit[] = +{ + { &CLSID_MultiPinMFT, MFT_CreateInstance }, +}; + +class CClassFactory : public IClassFactory +{ +public: + + static HRESULT CreateInstance( + REFCLSID clsid, // The CLSID of the object to create (from DllGetClassObject) + const CLASS_OBJECT_INIT *pClassObjectInits, // Array of class factory data. + size_t cClassObjectInits, // Number of elements in the array. + REFIID riid, // The IID of the interface to retrieve (from DllGetClassObject) + void **ppv // Receives a pointer to the interface. + ) + { + *ppv = NULL; + + HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; + + for (size_t i = 0; i < cClassObjectInits; i++) + { + if (clsid == *pClassObjectInits[i].pClsid) + { + IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate); + + if (pClassFactory) + { + hr = pClassFactory->QueryInterface(riid, ppv); + pClassFactory->Release(); + } + else + { + hr = E_OUTOFMEMORY; + } + break; // match found + } + } + return hr; + } + + // IUnknown methods + IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv) + { +#if 0 + static const QITAB qit[] = + { + QITABENT(CClassFactory, IClassFactory), + { 0 } + }; + return QISearch(this, qit, riid, ppv); + +#else + if (riid == __uuidof(IClassFactory)) + { + *ppv = static_cast< IClassFactory* >(this); + AddRef(); + } + return S_OK; +#endif + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + IFACEMETHODIMP_(ULONG) Release() + { + long cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) + { + delete this; + } + return cRef; + } + + // IClassFactory methods + + IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv) + { + return punkOuter ? CLASS_E_NOAGGREGATION : m_pfnCreate(riid, ppv); + } + + IFACEMETHODIMP LockServer(BOOL fLock) + { + if (fLock) + { + DllAddRef(); + } + else + { + DllRelease(); + } + return S_OK; + } + +private: + + CClassFactory(PFNCREATEINSTANCE pfnCreate) : m_cRef(1), m_pfnCreate(pfnCreate) + { + DllAddRef(); + } + + ~CClassFactory() + { + DllRelease(); + } + + long m_cRef; + PFNCREATEINSTANCE m_pfnCreate; +}; + + + +// +// Standard DLL functions +// + +STDMETHODIMP_(BOOL) WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, void *) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hModule = (HMODULE)hInstance; + DisableThreadLibraryCalls(hInstance); +#ifdef MF_WPP + WPP_INIT_TRACING(L"MultiPinMft"); +#endif + } + else + if (dwReason == DLL_PROCESS_DETACH) + { +#ifdef MF_WPP + WPP_CLEANUP(); +#endif + } + return TRUE; +} + +STDMETHODIMP DllCanUnloadNow() +{ + HRESULT hr = ((g_cRefModule == 0) && (CDMFTModuleLifeTimeManager::GetDMFTObjCount() == 0)) ? S_OK : S_FALSE; + // + // Debug object lifetimes + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! returning %d %d %!HRESULT!", + g_cRefModule, + CDMFTModuleLifeTimeManager::GetDMFTObjCount(), + hr); + + return hr; + +} + +_Check_return_ +STDAPI DllGetClassObject(_In_ REFCLSID clsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv) +{ + return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv); +} + +STDMETHODIMP DllRegisterServer() +{ + assert(g_hModule != NULL); + + // Register the CLSID for CoCreateInstance. + HRESULT hr = RegisterObject(g_hModule, CLSID_MultiPinMFT, TEXT("Multiple MFTs"), TEXT("Both")); + + return hr; +} + +STDMETHODIMP DllUnregisterServer() +{ + // Unregister the CLSID. + UnregisterObject(CLSID_MultiPinMFT); + + return S_OK; +} + + +// Converts a CLSID into a string with the form "CLSID\{clsid}" +STDMETHODIMP CreateObjectKeyName(REFGUID guid, _Out_writes_(cchMax) PWSTR pszName, DWORD cchMax) +{ + const DWORD chars_in_guid = 39; + + // convert CLSID uuid to string + OLECHAR szCLSID[chars_in_guid]; + HRESULT hr = StringFromGUID2(guid, szCLSID, chars_in_guid); + if (SUCCEEDED(hr)) + { + // Create a string of the form "CLSID\{clsid}" + hr = StringCchPrintf((STRSAFE_LPWSTR)pszName, cchMax, TEXT("Software\\Classes\\CLSID\\%ls"), szCLSID); + } + return hr; +} + +// Creates a registry key (if needed) and sets the default value of the key +STDMETHODIMP CreateRegKeyAndValue(HKEY hKey, PCWSTR pszSubKeyName, PCWSTR pszValueName, + PCWSTR pszData, PHKEY phkResult) +{ + *phkResult = NULL; + LONG lRet = RegCreateKeyExW( + hKey, pszSubKeyName, + 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, phkResult, NULL); + + if (lRet == ERROR_SUCCESS) + { + lRet = RegSetValueExW( + (*phkResult), + pszValueName, 0, REG_SZ, + (LPBYTE) pszData, + ((DWORD) wcslen(pszData) + 1) * sizeof(WCHAR) + ); + + if (lRet != ERROR_SUCCESS) + { + RegCloseKey(*phkResult); + } + } + + return HRESULT_FROM_WIN32(lRet); +} + +// Creates the registry entries for a COM object. + +HRESULT RegisterObject(HMODULE hModule, const GUID& guid, const TCHAR *pszDescription, const TCHAR *pszThreadingModel) +{ + HKEY hKey = NULL; + HKEY hSubkey = NULL; + TCHAR achTemp[MAX_PATH]; + + // Create the name of the key from the object's CLSID + HRESULT hr = CreateObjectKeyName(guid, achTemp, MAX_PATH); + + // Create the new key. + if (SUCCEEDED(hr)) + { + hr = CreateRegKeyAndValue(HKEY_LOCAL_MACHINE, achTemp, NULL, pszDescription,&hKey); + } + + if (SUCCEEDED(hr)) + { + (void)GetModuleFileName(hModule, achTemp, MAX_PATH); + + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + // Create the "InprocServer32" subkey + if (SUCCEEDED(hr)) + { + hr = CreateRegKeyAndValue(hKey, L"InProcServer32", NULL, achTemp, &hSubkey); + RegCloseKey(hSubkey); + } + + // Add a new value to the subkey, for "ThreadingModel" = <threading model> + if (SUCCEEDED(hr)) + { + hr = CreateRegKeyAndValue(hKey, L"InProcServer32", L"ThreadingModel", pszThreadingModel, &hSubkey); + RegCloseKey(hSubkey); + } + + // close hkeys + RegCloseKey(hKey); + return hr; +} + +// Deletes the registry entries for a COM object. + +HRESULT UnregisterObject(const GUID& guid) +{ + WCHAR achTemp[MAX_PATH]; + + HRESULT hr = CreateObjectKeyName(guid, achTemp, MAX_PATH); + if (SUCCEEDED(hr)) + { + // Delete the key recursively. + LONG lRes = RegDeleteTree(HKEY_LOCAL_MACHINE, achTemp); + hr = HRESULT_FROM_WIN32(lRes); + } + return hr; +} + + diff --git a/AVStream/sampledevicemft/mftpeventgenerator.cpp b/AVStream/sampledevicemft/mftpeventgenerator.cpp new file mode 100644 index 00000000..72b395ff --- /dev/null +++ b/AVStream/sampledevicemft/mftpeventgenerator.cpp @@ -0,0 +1,250 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" +#include "common.h" +#include "mftpeventgenerator.h" + + +#define TP_SCOPE_TRACE TP_NORMAL +#define DH_THIS_FILE DH_DEVPROXY + +#ifdef MF_WPP +#include "mftpeventgenerator.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif + +CMediaEventGenerator::CMediaEventGenerator () : + m_nRefCount(0), + m_pQueue(NULL), + m_bShutdown(FALSE) +{ + //Call this explicit... + InitMediaEventGenerator(); +} + +STDMETHODIMP CMediaEventGenerator::InitMediaEventGenerator( + void + ) +{ + + return MFCreateEventQueue(&m_pQueue); + +} + +STDMETHODIMP_(ULONG) CMediaEventGenerator::AddRef( + void + ) +{ + return InterlockedIncrement(&m_nRefCount); +} + +STDMETHODIMP_(ULONG) CMediaEventGenerator::Release( + void + ) +{ + ULONG uCount = InterlockedDecrement(&m_nRefCount); + + if (uCount == 0) + { + delete this; + } + return uCount; +} + +STDMETHODIMP CMediaEventGenerator::QueryInterface( + _In_ REFIID iid, + _COM_Outptr_ void** ppv) +{ + HRESULT hr = S_OK; + + *ppv = NULL; + + if (iid == __uuidof(IUnknown) || iid == __uuidof(IMFMediaEventGenerator)) + { + *ppv = static_cast<IMFMediaEventGenerator*>(this); + AddRef(); + } + else + { + hr = E_NOINTERFACE; + DMFTCHECKHR_GOTO(hr, done); + } + +done: + + return hr; +} + +// +// IMediaEventGenerator methods +// +STDMETHODIMP CMediaEventGenerator::BeginGetEvent( + _In_ IMFAsyncCallback* pCallback, + _In_ IUnknown* pState + ) +{ + HRESULT hr = S_OK; + //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT BeginGetEvent called"); + m_critSec.Lock(); + + hr = CheckShutdown(); + + if (SUCCEEDED(hr)) + { + hr = m_pQueue->BeginGetEvent(pCallback, pState); + } + + m_critSec.Unlock(); + + return hr; +} + +STDMETHODIMP CMediaEventGenerator::EndGetEvent( + _In_ IMFAsyncResult* pResult, + _Outptr_result_maybenull_ IMFMediaEvent** ppEvent + ) +{ + HRESULT hr = S_OK; + //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT EndGetEvent called"); + m_critSec.Lock(); + + hr = CheckShutdown(); + + if (SUCCEEDED(hr)) + { + hr = m_pQueue->EndGetEvent(pResult, ppEvent); + } + + m_critSec.Unlock(); + + return hr; +} + +STDMETHODIMP CMediaEventGenerator::GetEvent( + _In_ DWORD dwFlags, + _Outptr_result_maybenull_ IMFMediaEvent** ppEvent + ) +{ + // + // Because GetEvent can block indefinitely, it requires + // a slightly different locking strategy. + // + HRESULT hr = S_OK; + //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT GetEvent called"); + IMFMediaEventQueue *pQueue = NULL; + + m_critSec.Lock(); + + hr = CheckShutdown(); + // + // Store the pointer in a local variable, so that another thread + // does not release it after we leave the critical section. + // + if (SUCCEEDED(hr)) + { + pQueue = m_pQueue; + } + + m_critSec.Unlock(); + + if (SUCCEEDED(hr)) + { + hr = pQueue->GetEvent(dwFlags, ppEvent); + } + + return hr; +} + +STDMETHODIMP CMediaEventGenerator::QueueEvent( + _In_ MediaEventType met, + _In_ REFGUID extendedType, + _In_ HRESULT hrStatus, + _In_opt_ const PROPVARIANT* pvValue + ) +{ + HRESULT hr = S_OK; + //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT QueueEvent called"); + m_critSec.Lock(); + + hr = CheckShutdown(); + + if (SUCCEEDED(hr)) + { + + hr = m_pQueue->QueueEventParamVar( + met, + extendedType, + hrStatus, + pvValue + ); + } + + m_critSec.Unlock(); + + return hr; +} + +STDMETHODIMP CMediaEventGenerator::ShutdownEventGenerator( + void + ) +{ + HRESULT hr = S_OK; + + // MFWMITRACE( DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : entering ..."); + + m_critSec.Lock(); + + hr = CheckShutdown(); + + if (SUCCEEDED(hr)) + { + if (m_pQueue) + { + hr = m_pQueue->Shutdown(); + //MFWMITRACE( DH_THIS_FILE, TP_NORMAL, __FUNCTION__ "Event Generator Queue shutdown hr = %x", hr); + } + SAFE_RELEASE(m_pQueue); + m_bShutdown = TRUE; + } + m_critSec.Unlock(); + + // MFWMITRACE( DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : exiting..."); + + return hr; +} + +STDMETHODIMP CMediaEventGenerator::QueueEvent( + _In_ IMFMediaEvent* pEvent + ) +{ + HRESULT hr = S_OK; + //MFWMITRACE(DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : QueueEvent 1 ..."); + m_critSec.Lock(); + + hr = CheckShutdown(); + + if (SUCCEEDED(hr)) + { + if (m_pQueue) + { + hr = m_pQueue->QueueEvent(pEvent); + } + } + + m_critSec.Unlock(); + return hr; +} + +CMediaEventGenerator::~CMediaEventGenerator ( + void + ) +{ + ShutdownEventGenerator(); + //MFASSERT(m_bShutdown); + //MFASSERT(m_nRefCount == 0); +} diff --git a/AVStream/sampledevicemft/mftpeventgenerator.h b/AVStream/sampledevicemft/mftpeventgenerator.h new file mode 100644 index 00000000..2ddae218 --- /dev/null +++ b/AVStream/sampledevicemft/mftpeventgenerator.h @@ -0,0 +1,94 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// +#pragma once + +class CMediaEventGenerator : + public IMFMediaEventGenerator +{ + +public: + + // + // IUnknown + // + STDMETHOD_(ULONG, AddRef)( + void + ); + + STDMETHOD_(ULONG, Release)( + void + ); + + STDMETHOD(QueryInterface)( + _In_ REFIID iid, + _COM_Outptr_ void** ppv); + + + // + // IMFMediaEventGenerator + // + STDMETHOD(BeginGetEvent)( + _In_ IMFAsyncCallback* pCallback, + _In_ IUnknown* pState + ); + + STDMETHOD(EndGetEvent)( + _In_ IMFAsyncResult* pResult, + _Outptr_result_maybenull_ IMFMediaEvent** ppEvent + ); + + STDMETHOD(GetEvent)( + _In_ DWORD dwFlags, + _Outptr_result_maybenull_ IMFMediaEvent** ppEvent + ); + + STDMETHOD(QueueEvent)( + _In_ MediaEventType met, + _In_ REFGUID extendedType, + _In_ HRESULT hrStatus, + _In_opt_ const PROPVARIANT* pvValue + ); + + STDMETHOD(QueueEvent)( + _In_ IMFMediaEvent* pEvent + ); + +protected: + + CMediaEventGenerator( + void + ); + + virtual ~CMediaEventGenerator ( + void + ); + // + // Utility Methods + // + STDMETHOD(ShutdownEventGenerator)( + void + ); + + STDMETHOD (InitMediaEventGenerator)( + void + ); + + __inline HRESULT (CheckShutdown)( + void + ) const + { + return (m_bShutdown? MF_E_SHUTDOWN : S_OK); + } + +private: + + long m_nRefCount; + CCritSec m_critSec; + IMFMediaEventQueue* m_pQueue; + BOOL m_bShutdown; +}; diff --git a/AVStream/sampledevicemft/multipinmft.cpp b/AVStream/sampledevicemft/multipinmft.cpp new file mode 100644 index 00000000..ea7fd892 --- /dev/null +++ b/AVStream/sampledevicemft/multipinmft.cpp @@ -0,0 +1,2453 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" +#include "multipinmft.h" +#ifdef MF_WPP +#include "multipinmft.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif +// +//Note since MFT_UNIQUE_METHOD_NAMES is defined all the functions of IMFTransform have the Mft suffix.. +// +extern const CLSID CLSID_HwMFTActivate; + +#if _NEED_MFTLOCKING_ +#define MFTLOCKED() {\ + UINT32 punValue = FALSE; \ + hr = GetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, &punValue);\ +if (FAILED(hr) || punValue == FALSE){\ + return MF_E_TRANSFORM_ASYNC_LOCKED; \ +}\ +} +#else + +#define MFTLOCKED() + +#endif + +CMultipinMft::CMultipinMft() +: m_nRefCount( 0 ), + m_InputPinCount( 0 ), + m_OutputPinCount( 0 ), + m_dwWorkQueueId ( MFASYNC_CALLBACK_QUEUE_MULTITHREADED ), + m_lWorkQueuePriority ( 0 ), + m_spAttributes( nullptr ), + m_spSourceTransform( nullptr ), + m_PhotoTriggerSent(false), + m_filterHasIndependentPin( false ), + m_FilterInPhotoSequence( false ), + m_filterInWarmStart(false) +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) + , m_spPhotoConfirmationCallback(nullptr) +#endif +{ + ComPtr<IMFAttributes> pAttributes = nullptr; + MFCreateAttributes( &pAttributes, 0 ); + pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE ); + pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ); + pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE ); + pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" ); + m_spAttributes = pAttributes; +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) + m_guidPhotoConfirmationSubtype = MFVideoFormat_NV12; +#endif +} + +CMultipinMft::~CMultipinMft( ) +{ + CBasePin *pioPin = NULL; + + for ( ULONG ulIndex = 0, ulSize = (ULONG) m_InPins.size(); ulIndex < ulSize; ulIndex++ ) + { + pioPin = m_InPins[ ulIndex ]; + SAFERELEASE( pioPin ); + } + m_InPins.clear(); + + for (ULONG ulIndex = 0, ulSize = (ULONG) m_OutPins.size(); ulIndex < ulSize; ulIndex++) + { + pioPin = m_OutPins[ ulIndex ]; + SAFERELEASE( pioPin ); + } + m_OutPins.clear(); + m_spSourceTransform = nullptr; + +} + +STDMETHODIMP_(ULONG) CMultipinMft::AddRef( + void + ) +{ + return InterlockedIncrement(&m_nRefCount); +} + +STDMETHODIMP_(ULONG) CMultipinMft::Release( + void + ) +{ + ULONG uCount = InterlockedDecrement(&m_nRefCount); + + if ( uCount == 0 ) + { + delete this; + } + return uCount; +} + +STDMETHODIMP CMultipinMft::QueryInterface( + _In_ REFIID iid, + _COM_Outptr_ void** ppv + ) +{ + + HRESULT hr = S_OK; + *ppv = NULL; + + if ((iid == __uuidof(IMFDeviceTransform)) || (iid == __uuidof(IUnknown))) + { + *ppv = static_cast< IMFDeviceTransform* >(this); + AddRef(); + } + else + if ( iid == __uuidof( IMFMediaEventGenerator ) ) + { + *ppv = static_cast< IMFMediaEventGenerator* >(this); + AddRef(); + } + else + if ( iid == __uuidof( IMFShutdown ) ) + { + *ppv = static_cast< IMFShutdown* >( this ); + AddRef(); + } +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + else + if (iid == __uuidof(IMFTransform)) + { + *ppv = static_cast< IMFTransform* >(this); + AddRef(); + } +#endif + else + if ( iid == __uuidof( IKsControl ) ) + { + *ppv = static_cast< IKsControl* >( this ); + AddRef(); + } + else + if ( iid == __uuidof( IMFRealTimeClientEx ) ) + { + *ppv = static_cast< IMFRealTimeClientEx* >( this ); + AddRef(); + } +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) + else + if (iid == __uuidof(IMFCapturePhotoConfirmation)) + { + *ppv = static_cast< IMFCapturePhotoConfirmation* >(this); + AddRef(); + } + else + if (iid == __uuidof(IMFGetService)) + { + *ppv = static_cast< IMFGetService* >(this); + AddRef(); + } +#endif + else + { + hr = E_NOINTERFACE; + } + return hr; +} + +/*++ + Description: + This function is the entry point of the transform + The following things may be initialized here + 1) Query for MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL on the attributes supplied + 2) From the IUnknown acquired get the IMFTransform interface. + 3) Get the stream count.. The output streams are of consequence to the tranform. + The input streams should correspond to the output streams exposed by the source transform + acquired from the Attributes supplied. + 4) Get the IKSControl which is used to send KSPROPERTIES, KSEVENTS and KSMETHODS to the driver for the filer level. Store it in your filter class + 5) Get the OutPutStreamAttributes for the output pins of the source transform. This can further be used to QI and acquire + the IKSControl related to the specific pin. This can be used to send PIN level KSPROPERTIES, EVENTS and METHODS to the pins + 6) Create the output pins + +--*/ + +STDMETHODIMP CMultipinMft::InitializeTransform ( + _In_ IMFAttributes *pAttributes + ) +{ + HRESULT hr = S_OK; + ComPtr<IUnknown> spFilterUnk = nullptr; + DWORD *pcInputStreams = NULL, *pcOutputStreams = NULL; + DWORD inputStreams = 0; + DWORD outputStreams = 0; + GUID* outGuids = NULL; + GUID streamCategory = GUID_NULL; + + DMFTCHECKNULL_GOTO( pAttributes, done, E_INVALIDARG ); + // + //The attribute passed with MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL is the source transform. This generally represents a filter + //This needs to be stored so that we know the device properties. We cache it. We query for the IKSControl which is used to send + //controls to the driver. + // + DMFTCHECKHR_GOTO( pAttributes->GetUnknown( MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL,IID_PPV_ARGS( &spFilterUnk ) ),done ); + + DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done ); + + DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done ); + + DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamCount( &inputStreams, &outputStreams ), done ); + + spFilterUnk = nullptr; + + // + //The number of input pins created by the device transform should match the pins exposed by + //the source transform i.e. outputStreams from SourceTransform or DevProxy = Input pins of the Device MFT + // + + if ( inputStreams > 0 || outputStreams > 0 ) + { + pcInputStreams = new DWORD[ inputStreams ]; + DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY); + + pcOutputStreams = new DWORD[ outputStreams ]; + DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY ); + + DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamIDs( inputStreams, pcInputStreams, + outputStreams, + pcOutputStreams ),done ); + + // + // Output pins from DevProxy = Input pins of device MFT.. We are the first transform in the pipeline before MFT0 + // + + for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ ) + { + ComPtr<IMFAttributes> pInAttributes = nullptr; + + DMFTCHECKHR_GOTO( m_spSourceTransform->GetOutputStreamAttributes(pcOutputStreams[ulIndex], pInAttributes.GetAddressOf()), done); + + DMFTCHECKHR_GOTO( pInAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &streamCategory), done); + + if ( IsEqualCLSID( streamCategory, PINNAME_IMAGE ) ) + { + //We have independent pins.. + m_filterHasIndependentPin = true; + } + CInPin *pInPin = nullptr; + if (IsEqualCLSID(streamCategory, AVSTREAM_CUSTOM_PIN_IMAGE)) + { + pInPin = new CCustomPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this); + DMFTCHECKNULL_GOTO( pInPin, done, E_OUTOFMEMORY); + // + // Since the custom pin is an input pin too we will push it + // in the input pins list. This is however not being connected + // to the output in this sample. + m_CustomPinCount++; + } + else + { + pInPin = new CInPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this); + DMFTCHECKNULL_GOTO(pInPin, done, E_OUTOFMEMORY); + } + + hr = ExceptionBoundary([this,pInPin]() + { + m_InPins.push_back(pInPin); + }); + + DMFTCHECKHR_GOTO(hr, done); + DMFTCHECKHR_GOTO( pInPin->Init(m_spSourceTransform.Get() ), done); + + + pInPin->AddRef(); + + } + // + // If we have just one output stream exposed off the source transform create a one to three pin + // + if ( ( outputStreams == 1 ) && IsEqualGUID( streamCategory, PINNAME_VIDEO_CAPTURE ) ) + { + outputStreams = 3; + outGuids = new GUID [ outputStreams ]; + DMFTCHECKNULL_GOTO(outGuids, done, E_OUTOFMEMORY); + + m_OutPins.resize(outputStreams, nullptr); + + CInPin *piPin = (CInPin *)m_InPins[0]; + + *outGuids = PINNAME_VIDEO_CAPTURE; + *( outGuids + 1 ) = PINNAME_VIDEO_PREVIEW; + *(outGuids + 2) = PINNAME_IMAGE; //PINNAME_IMAGE for independent pin and PINNAME_VIDEO_STILL for dependent pin!! + + for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ ) + { + ComPtr<IKsControl> pKsControl = NULL; + COutPin *poPin = nullptr; + + DMFTCHECKHR_GOTO( piPin->QueryInterface(IID_PPV_ARGS( &pKsControl ) ), done); + + hr = ExceptionBoundary([&]() + { + poPin = new COutPin(ulIndex, this, pKsControl.Get()); + }); + + DMFTCHECKHR_GOTO(hr, done); + + DMFTCHECKNULL_GOTO( poPin,done, E_OUTOFMEMORY ); + + DMFTCHECKHR_GOTO( BridgeInputPinOutputPin( piPin, poPin ),done ); + + DMFTCHECKHR_GOTO( poPin->SetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, outGuids[ ulIndex ] ),done ); + + DMFTCHECKHR_GOTO( poPin->SetUINT32( MF_DEVICESTREAM_STREAM_ID, ulIndex ),done ); + + m_OutPins[ ulIndex ] = poPin; + poPin->AddRef(); + + } + } + else + { + // + //Create one on one mapping + // + + for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++) + { + ULONG ulPinIndex = 0; + GUID pinGuid = GUID_NULL; + ComPtr< IKsControl > pKsControl = nullptr; + + CInPin *piPin = ( CInPin * )m_InPins[ ulIndex ]; + + if (piPin) + { + BOOL isCustom = false; + if ( SUCCEEDED( CheckCustomPin( piPin, &isCustom )) && ( isCustom ) ) + { + // + // In this sample we are not connecting the custom pin to the output + // This is because we really have no way of testing the custom pin with the + // pipeline. + // This however can be changed if the custom media type is converted here in + // the device MFT and later exposed to the pipeline.. + // + continue; + } + ulPinIndex = piPin->streamId(); + + DMFTCHECKHR_GOTO(piPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinGuid), done); + + DMFTCHECKHR_GOTO(piPin->QueryInterface(IID_PPV_ARGS(&pKsControl)), done); + + COutPin *poPin = new COutPin(ulPinIndex, this, pKsControl.Get()); + + DMFTCHECKNULL_GOTO(poPin, done, E_OUTOFMEMORY); + + DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, pinGuid), done); + + DMFTCHECKHR_GOTO(poPin->SetUINT32(MF_DEVICESTREAM_STREAM_ID, ulPinIndex), done); + +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + // + // If we wish to load MFT0 as well as Device MFT then we should be doing the following + // Copy over the GUID attribute MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID from the input + // pin to the output pin. This is because Device MFT is the new face of the filter now + // and MFT0 will now get loaded for the output pins exposed from Device MFT rather than + // DevProxy! + // + + GUID guidMFT0 = GUID_NULL; + + hr = piPin->GetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, &guidMFT0); + + if (SUCCEEDED(hr)) + { + // + // This stream has an MFT0 .. Attach the GUID to the Outpin pin attribute + // The downstream will query this attribute on the pins exposed from device MFT + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! setting Mft0 guid on pin %d", ulIndex); + + DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, guidMFT0), done); + + DMFTCHECKHR_GOTO(poPin->SetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT, + static_cast< IUnknown* >(static_cast < IKsControl * >(this))), done); + + } + else + { + // Reset Error.. MFT0 absence should not be an error + hr = S_OK; + } +#endif + DMFTCHECKHR_GOTO(BridgeInputPinOutputPin(piPin, poPin), done); + hr = ExceptionBoundary([&]() + { + m_OutPins.push_back(poPin); + }); + DMFTCHECKHR_GOTO(hr, done); + } + } + } + } + + m_InputPinCount = ULONG ( m_InPins.size() ); + m_OutputPinCount = ULONG ( m_OutPins.size() ); + + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!",hr,hr); + + if ( pcInputStreams ) + { + delete[ ] ( pcInputStreams ); + } + if ( pcOutputStreams ) + { + delete[ ] ( pcOutputStreams ); + } + if ( outGuids ) + { + delete [] ( outGuids ); + } + if ( FAILED( hr ) ) + { + //Release the pins and the resources acquired + while ( m_InPins.size() > 0 ) + { + CInPin *pInPin = nullptr; + pInPin = ( CInPin* )m_InPins.back(); + m_InPins.pop_back(); + SAFERELEASE( pInPin ); + } + while ( m_OutPins.size() > 0 ) + { + COutPin *pin = nullptr; + pin = ( COutPin* )m_OutPins.back(); + m_OutPins.pop_back(); + SAFERELEASE( pin ); + } + // + // Simply clear the custom pins since the input pins must have deleted the pin + // + m_spSourceTransform = nullptr; + } + return hr; +} + + +STDMETHODIMP CMultipinMft::SetWorkQueueEx( + _In_ DWORD dwWorkQueueId, + _In_ LONG lWorkItemBasePriority + ) +/*++ + Description: + + Implements IMFRealTimeClientEx::SetWorkQueueEx function + +--*/ +{ + CAutoLock lock( m_critSec ); + // + // Cache the WorkQueuId and WorkItemBasePriority + // + m_dwWorkQueueId = dwWorkQueueId; + m_lWorkQueuePriority = lWorkItemBasePriority; + return S_OK; + +} + +// +// IMFDeviceTransform functions +// +STDMETHODIMP CMultipinMft::GetStreamCount( + _Inout_ DWORD *pdwInputStreams, + _Inout_ DWORD *pdwOutputStreams + ) +/*++ + Description: Implements IMFTransform::GetStreamCount function +--*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + + + *pdwInputStreams = m_InputPinCount; + *pdwOutputStreams = m_OutputPinCount; + + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + +// +//Doesn't striclt conform to GetStreamIDs on IMFTransform Interface! +// +STDMETHODIMP CMultipinMft::GetStreamIDs( + _In_ DWORD dwInputIDArraySize, + _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs, + _In_ DWORD dwOutputIDArraySize, + _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)), + _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs + ) +/*++ + Description: + Implements IMFTransform::GetStreamIDs function +--*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + + MFTLOCKED(); + + if ( ( dwInputIDArraySize < m_InputPinCount ) && ( dwOutputIDArraySize < m_OutputPinCount ) ) + { + hr = MF_E_BUFFERTOOSMALL; + goto done; + } + + if ( dwInputIDArraySize ) + { + DMFTCHECKNULL_GOTO( pdwInputIDs, done, E_POINTER ); + for ( DWORD dwIndex = 0; dwIndex < ((dwInputIDArraySize > m_InputPinCount) ? m_InputPinCount: + dwInputIDArraySize); dwIndex++ ) + { + pdwInputIDs[ dwIndex ] = ( m_InPins[dwIndex] )->streamId(); + } + } + + if ( dwOutputIDArraySize ) + { + DMFTCHECKNULL_GOTO( pdwOutputIDs, done, E_POINTER ); + for ( DWORD dwIndex = 0; dwIndex < ((dwOutputIDArraySize > m_OutputPinCount)? m_OutputPinCount: + dwOutputIDArraySize); dwIndex++ ) + { + pdwOutputIDs[ dwIndex ] = (m_OutPins[ dwIndex ])->streamId(); + } + } +done: + return hr; +} + +/*++ +Name: CMultipinMft::GetInputAvailableType +Description: +Implements IMFTransform::GetInputAvailableType function. This function +gets the media type supported by the specified stream based on the +index dwTypeIndex. +--*/ +STDMETHODIMP CMultipinMft::GetInputAvailableType( + _In_ DWORD dwInputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType + ) +{ + HRESULT hr = S_OK; + MFTLOCKED(); + + + CInPin *piPin = ( CInPin* )GetInPin( dwInputStreamID ); + + DMFTCHECKNULL_GOTO( piPin, done, MF_E_INVALIDSTREAMNUMBER ); + + *ppMediaType = nullptr; + + hr = piPin->GetOutputAvailableType( dwTypeIndex,ppMediaType ); + + if (FAILED(hr)) + { + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!", + dwInputStreamID, + dwTypeIndex, + hr); + + } + +done: + return hr; +} + +STDMETHODIMP CMultipinMft::GetOutputAvailableType( + _In_ DWORD dwOutputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType + ) +/*++ + Description: + + Implements IMFTransform::GetOutputAvailableType function. This function + gets the media type supported by the specified stream based on the + index dwTypeIndex. + +--*/ +{ + HRESULT hr = S_OK; + MFTLOCKED(); + + DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG); + + COutPin*poPin = ( COutPin* )GetOutPin( dwOutputStreamID ); + + DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER ); + + *ppMediaType = nullptr; + + hr = poPin->GetOutputAvailableType( dwTypeIndex, ppMediaType ); + + if ( FAILED( hr ) ) + { + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!", + dwOutputStreamID, + dwTypeIndex, + hr ); + } + +done: + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputCurrentType( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType + ) +/*++ + Description: + Implements IMFTransform::GetInputCurrentType function. This function + returns the current media type set on the specified stream. +--*/ +{ + // + //The input current types will not come to this transform. + //The outputs of this transform matter. The DTM manages the + //output of this transform and the inptuts of the source transform + // + UNREFERENCED_PARAMETER(dwInputStreamID); + UNREFERENCED_PARAMETER(ppMediaType); + return S_OK; +} + +STDMETHODIMP CMultipinMft::GetOutputCurrentType( + _In_ DWORD dwOutputStreamID, + _Out_ IMFMediaType** ppMediaType + ) +/*++ + Description: + + Implements IMFTransform::GetOutputCurrentType function. This function + returns the current media type set on the specified stream. + +--*/ +{ + HRESULT hr = S_OK; + MFTLOCKED(); + CAutoLock lock( m_critSec ); + + DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG ); + + *ppMediaType = nullptr; + + COutPin *poPin = ( COutPin* )GetOutPin( dwOutputStreamID ); + + DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER ); + + DMFTCHECKHR_GOTO( poPin->getMediaType( ppMediaType ),done ); + + DMFTCHECKNULL_GOTO( *ppMediaType, done, MF_E_TRANSFORM_TYPE_NOT_SET ); + +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + + +STDMETHODIMP CMultipinMft::ProcessEvent( + _In_ DWORD dwInputStreamID, + _In_ IMFMediaEvent* pEvent + ) + /*++ + Description: + + Implements IMFTransform::ProcessEvent function. This function + processes events that come to the MFT. + + --*/ +{ + UNREFERENCED_PARAMETER(dwInputStreamID); + UNREFERENCED_PARAMETER(pEvent); + return S_OK; +} + + + +STDMETHODIMP CMultipinMft::ProcessMessage( + _In_ MFT_MESSAGE_TYPE eMessage, + _In_ ULONG_PTR ulParam + ) +/*++ + Description: + + Implements IMFTransform::ProcessMessage function. This function + processes messages coming to the MFT. + +--*/ +{ + HRESULT hr = S_OK; + MFTLOCKED(); + + UNREFERENCED_PARAMETER(ulParam); + + CAutoLock _lock( m_critSec ); + + printMessageEvent( eMessage ); + + switch ( eMessage ) + { + case MFT_MESSAGE_COMMAND_FLUSH: + // + //This is MFT wide flush.. Flush all output pins + // + (VOID)FlushAllStreams(); + break; + case MFT_MESSAGE_COMMAND_DRAIN: + // + //There is no draining for Device MFT. Just kept here for reference + // + break; + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + // + //No op for device MFTs + // + break; + case MFT_MESSAGE_SET_D3D_MANAGER: + { + if ( ulParam ) + { + ComPtr< IDirect3DDeviceManager9 > spD3D9Manager; + ComPtr< IMFDXGIDeviceManager > spDXGIManager; + + hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spD3D9Manager ) ); + if ( SUCCEEDED( hr ) ) + { + m_spDeviceManagerUnk = ( IUnknown* )ulParam; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IDirect3DDeviceManager9 %p, is passed", spD3D9Manager.Get() ); + } + else + { + hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spDXGIManager ) ); + if ( SUCCEEDED(hr) ) + { + m_spDeviceManagerUnk = (IUnknown*)ulParam; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IMFDXGIDeviceManager %p, is passed", spDXGIManager.Get()); + } + } + } + else + { + m_spDeviceManagerUnk = nullptr; + hr = S_OK; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC!IDirect3DDeviceManager9 was not passed in"); + } + } + break; + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + { + SetStreamingState( DeviceStreamState_Run ); + // + // Start Streaming custom pins if the device transfrom has any + // + SetStreamingStateCustomPins( DeviceStreamState_Run ); + } + break; + case MFT_MESSAGE_NOTIFY_END_STREAMING: + { + SetStreamingState(DeviceStreamState_Stop); + // + // Stop streaming custom pins if the device transform has any + // + SetStreamingStateCustomPins( DeviceStreamState_Stop ); + } + break; + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + { + SetStreamingState(DeviceStreamState_Stop); + } + break; + default: + ; + } + + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + +STDMETHODIMP CMultipinMft::ProcessInput( + _In_ DWORD dwInputStreamID, + _In_ IMFSample* pSample, + _In_ DWORD dwFlags + ) +/*++ + Description: + + Implements IMFTransform::ProcessInput function.This function is called + when the sourcetransform has input to feed. the pins will try to deliver the + samples to the active output pins conencted. if none are connected then just + returns the sample back to the source transform + +--*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER( dwFlags ); + + MFTLOCKED(); + + CInPin *inPin = ( CInPin* )GetInPin( dwInputStreamID ); + DMFTCHECKNULL_GOTO( inPin, done, E_INVALIDARG ); + + if ( !IsStreaming() ) + { + goto done; + } + + DMFTCHECKHR_GOTO( inPin->SendSample( pSample ), done ); + + QueueEvent( METransformHaveOutput, GUID_NULL, S_OK, NULL ); + +done: + SAFERELEASE( pSample ); + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; + +} + +STDMETHODIMP CMultipinMft::ProcessOutput( + _In_ DWORD dwFlags, + _In_ DWORD cOutputBufferCount, + _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, + _Out_ DWORD *pdwStatus +) +/*++ +Description: + +Implements IMFTransform::ProcessOutput function. This is called by the DTM when +the DT indicates it has samples to give. The DTM will send enough MFT_OUTPUT_DATA_BUFFER +pointers to be filled up as is the number of output pins available. The DT should traverse its +output pins and populate the corresponding MFT_OUTPUT_DATA_BUFFER with the samples available + +--*/ +{ + HRESULT hr = S_OK; + BOOL gotOne = false; + MFTLOCKED(); + UNREFERENCED_PARAMETER( dwFlags ); + + if (cOutputBufferCount > m_OutputPinCount ) + { + DMFTCHECKHR_GOTO( E_INVALIDARG, done ); + } + *pdwStatus = 0; + + for ( DWORD i = 0; i < cOutputBufferCount; i++ ) + { + DWORD dwStreamID = pOutputSamples[i].dwStreamID; + + COutPin *poPin = ( COutPin * )GetOutPin( dwStreamID ); + DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG ); + + if ( SUCCEEDED( poPin->ProcessOutput( dwFlags, &pOutputSamples[i], + pdwStatus ) ) ) + { + gotOne = true; + } + } + if (gotOne) + { + hr = S_OK; + } + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputStreamAttributes( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes + ) +/*++ + Description: + + Implements IMFTransform::GetInputStreamAttributes function. This function + gets the specified input stream's attributes. + +--*/ +{ + HRESULT hr = S_OK; + MFTLOCKED(); + + DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG ); + *ppAttributes = nullptr; + + CInPin *piPin = static_cast<CInPin*>(GetInPin( dwInputStreamID )); + + DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG ); + + hr = piPin->getPinAttributes(ppAttributes); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetOutputStreamAttributes( + _In_ DWORD dwOutputStreamID, + _Out_ IMFAttributes** ppAttributes + ) +/*++ + Description: + + Implements IMFTransform::GetOutputStreamAttributes function. This function + gets the specified output stream's attributes. + +--*/ +{ + HRESULT hr = S_OK; + MFTLOCKED(); + + DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG); + *ppAttributes = nullptr; + + COutPin *poPin = (COutPin *)GetOutPin(dwOutputStreamID); + + DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG ); + + DMFTCHECKHR_GOTO( poPin->getPinAttributes(ppAttributes), done ); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +_Requires_no_locks_held_ +STDMETHODIMP CMultipinMft::SetInputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::SetInputStreamState function. + Sets the input stream state. + + The control lock is not taken here. The lock is taken for operations on + output pins. This operation is a result of the DT notifying the DTM that + output pin change has resulted in the need for the input to be changed. In + this case the DTM sends a getpreferredinputstate and then this call + + --*/ +{ + HRESULT hr = S_OK; + CInPin *piPin = (CInPin*)GetInPin(dwStreamID); + DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER); + + DMFTCHECKHR_GOTO(piPin->SetInputStreamState(pMediaType, value, dwFlags),done); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value + ) +{ + HRESULT hr = S_OK; + CInPin *piPin = (CInPin*)GetInPin(dwStreamID); + + DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER); + + *value = piPin->GetState(); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +STDMETHODIMP CMultipinMft::SetOutputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState state, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::SetOutputStreamState function. + Sets the output stream state. This is called whenever the stream + is selected or deslected i.e. started or stopped. + + The control lock taken here and this operation should be atomic. + This function should check the input pins connected to the output pin + switch off the state of the input pin. Check if any other Pin connected + to the input pin is in a conflicting state with the state requested on this + output pin. Accordinly it calculates the media type to be set on the input pin + and the state to transition into. It then might recreate the other output pins + connected to it + --*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwFlags); + CAutoLock Lock(m_critSec); + + DMFTCHECKHR_GOTO(ChangeMediaTypeEx(dwStreamID, pMediaType, state),done); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetOutputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value + ) + /*++ + Description: + + Implements IMFdeviceTransform::GetOutputStreamState function. + Gets the output stream state. + Called by the DTM to checks states. Atomic operation. needs a lock + --*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + + COutPin *poPin = (COutPin *)GetOutPin(dwStreamID); + DMFTCHECKNULL_GOTO(poPin, done, MF_E_INVALIDSTREAMNUMBER); + + *value = poPin->GetState(); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputStreamPreferredState( + _In_ DWORD dwStreamID, + _Inout_ DeviceStreamState *value, + _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType + ) + /*++ + Description: + + Implements IMFdeviceTransform::GetInputStreamPreferredState function. + Gets the preferred state and the media type to be set on the input pin. + The lock is not held as this will always be called only when we notify + DTM to call us. We notify DTM only from the context on operations + happening on the output pin + --*/ +{ + HRESULT hr = S_OK; + CInPin *piPin = (CInPin*)GetInPin(dwStreamID); + DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER); + + piPin->GetInputStreamPreferredState(value, ppMediaType); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::FlushInputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::FlushInputStream function. + --*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwStreamIndex); + UNREFERENCED_PARAMETER(dwFlags); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::FlushOutputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::FlushOutputStream function. + Called by the DTM to flush streams + --*/ +{ + + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwFlags); + CAutoLock Lock(m_critSec); + + COutPin *poPin = (COutPin*)GetOutPin(dwStreamIndex); + DMFTCHECKNULL_GOTO(poPin, done, E_INVALIDARG); + + DeviceStreamState oldState = poPin->SetState(DeviceStreamState_Disabled); + + hr = poPin->FlushQueues(); + + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! failed %x = %!HRESULT!", hr, hr); + } + // + //Restore state + // + poPin->SetState(oldState); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +/*++ + Description: + + Called when the Device Transform gets a MFT_MESSAGE_COMMAND_FLUSH. We drain all the queues. + This is called in device source when the source gets end of streaming. + --*/ +STDMETHODIMP_(VOID) CMultipinMft::FlushAllStreams( + VOID + ) +{ + DeviceStreamState oldState; + for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ ) + { + COutPin *poPin = (COutPin *)m_OutPins[dwIndex]; + oldState = poPin->SetState(DeviceStreamState_Disabled); + poPin->FlushQueues(); + // + //Restore state + // + poPin->SetState(oldState); + } +} + + +// +// IKsControl interface functions +// +STDMETHODIMP CMultipinMft::KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pulBytesReturned + ) + /*++ + Description: + + Implements IKSProperty::KsProperty function. + used to pass control commands to the driver (generally) + This can be used to intercepted the control to figure out + if it needs to be propogated to the driver or not + --*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(pulBytesReturned); + DMFTCHECKNULL_GOTO(pProperty, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_INVALIDARG); + + // + // Enable Warm Start on All filters for the sample. Please comment out this + // section if this is not needed + // + if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl) + && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART)) + { + DMFTCHECKHR_GOTO(WarmStartHandler(pProperty, + ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned),done); + goto done; + } + + if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl) + && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Thumbnail sent %d",pProperty->Flags); + } + if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl) + &&(!filterHasIndependentPin())) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Extended Control %d Passed ",pProperty->Id); + switch (pProperty->Id) + { + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE: + hr = ExtendedPhotoModeHandler(pProperty, + ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned); + goto done; + break; + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE: + hr = ExtendedPhotoMaxFrameRate(pProperty, + ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned); + goto done; + break; + case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES: + hr = MaxVidFPS_PhotoResHandler(pProperty, + ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned); + goto done; + break; + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME: + hr = QPCTimeHandler(pProperty, + ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned); + goto done; + break; + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE: + hr = PhotoFrameRateHandler(pProperty, + ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned); + goto done; + break; + + } + } + else + if ((IsEqualCLSID(pProperty->Set, PROPSETID_VIDCAP_VIDEOCONTROL)) && + (pProperty->Id == KSPROPERTY_VIDEOCONTROL_MODE)) + { + // + //A photo trigger was sent!!! + //We need to set the event haveoutput + // + PKSPROPERTY_VIDEOCONTROL_MODE_S VideoControl = NULL; + if (sizeof(KSPROPERTY_VIDEOCONTROL_MODE_S) == ulDataLength) + { + VideoControl = (PKSPROPERTY_VIDEOCONTROL_MODE_S)pvPropertyData; + m_PhotoModeIsPhotoSequence = false; + + if (VideoControl->Mode == KS_VideoControlFlag_StartPhotoSequenceCapture) + { + // + //Signalling start of photo sequence + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Starting PhotoSequence Trigger"); + m_PhotoModeIsPhotoSequence = true; + setPhotoTriggerSent(true); + } + else + if (VideoControl->Mode == KS_VideoControlFlag_StopPhotoSequenceCapture) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Stopping PhotoSequence Trigger"); + m_PhotoModeIsPhotoSequence = false; + setPhotoTriggerSent(false); + } + else + { + // + //Normal trigger sent for single photo acquisition! + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Take Single Photo Trigger"); + setPhotoTriggerSent(true); + } + + } + + if (!filterHasIndependentPin()) + { + goto done; + } + } + hr = m_spIkscontrol->KsProperty(pProperty, + ulPropertyLength, + pvPropertyData, + ulDataLength, + pulBytesReturned); + + +done: + LPSTR guidStr = DumpGUIDA(pProperty->Set); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! g:%s p:%d exiting %x = %!HRESULT!", guidStr, pProperty->Id, hr, hr); + delete(guidStr); + return hr; +} + +STDMETHODIMP CMultipinMft::KsMethod( + _In_reads_bytes_(ulPropertyLength) PKSMETHOD pMethod, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pulBytesReturned + ) + /*++ + Description: + + Implements IKSProperty::KsMethod function. + --*/ +{ + return m_spIkscontrol->KsMethod( + pMethod, + ulPropertyLength, + pvPropertyData, + ulDataLength, + pulBytesReturned + ); +} + +STDMETHODIMP CMultipinMft::KsEvent( + _In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ) + /*++ + Description: + + Implements IKSProperty::KsEvent function. + --*/ +{ + + HRESULT hr = S_OK; + if (pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl) && + (pEvent->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control"); + // + // For the Sample the warmstate handlers are supported by Device MFT and not passed to driver + // + hr = m_eventHandler.KSEvent(pEvent, + ulEventLength, + pEventData, + ulDataLength, + pBytesReturned + ); + goto done; + } + + if ((pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl)) + && (!filterHasIndependentPin())) + { + // + // Important: Extended controls will send events which are strictly + // One shot. The event comes first where it should be duped and stored, + // the control comes next. The event should be set after control completes + // and it should be then closed. + // The below code handles only certain events needed for + // implementing photo sequence. For a complete exhaustive + // list refer documentation. + // + switch (pEvent->Id) + { + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE: + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE: + case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES: + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME: + case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE: + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control"); + // + // Let the event handler handle the event + // + DMFTCHECKHR_GOTO(m_eventHandler.KSEvent(pEvent, + ulEventLength, + pEventData, + ulDataLength, + pBytesReturned + ),done); + goto done; + } + } + } + // + // All the Events we don't handle should be sent to the driver! + // + hr = m_spIkscontrol->KsEvent(pEvent, + ulEventLength, + pEventData, + ulDataLength, + pBytesReturned); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) +// +//IMFGetService functions +// + +STDMETHODIMP CMultipinMft::GetService( + __in REFGUID guidService, + __in REFIID riid, + __deref_out LPVOID* ppvObject + ) +{ + // + //This doesn't necessarily need to be a GetService function, but this is just so that the + //pipeline implementation and the Device transform implementation is consistent. + //In this sample the photoconfirmation interface is implementated by the same class + //we can delegate it later to any of the pins if needed + // + UNREFERENCED_PARAMETER(guidService); + if (riid == __uuidof(IMFCapturePhotoConfirmation)) + { + return QueryInterface(riid, ppvObject); + } + else + return MF_E_UNSUPPORTED_SERVICE; + + +} + +// +//IMFCapturePhotoConfirmation functions implemented +// + +STDMETHODIMP CMultipinMft::SetPhotoConfirmationCallback( + _In_ IMFAsyncCallback* pNotificationCallback + ) +{ + CAutoLock Lock(m_critSec); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting PhotoConfirmation %p, is passed", pNotificationCallback); + + m_spPhotoConfirmationCallback = pNotificationCallback; + return S_OK; +} +STDMETHODIMP CMultipinMft::SetPixelFormat( + _In_ GUID subtype + ) +{ + m_guidPhotoConfirmationSubtype = subtype; + return S_OK; +} +STDMETHODIMP CMultipinMft::GetPixelFormat( + _Out_ GUID* subtype + ) +{ + *subtype = m_guidPhotoConfirmationSubtype; + return S_OK; +} + +#endif + + + +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + +// +// IMFTransform function(s). +// + +// +// Note: This is the only IMFTransform function which is not a redirector to the +// DeviceTransform functions. The rest of IMFTransform functions are in the file common.h +// This function returns the IMFAttribute created for Device MFT. If DMFT is +// not loaded (usually )MFT0's call to GetAttributes will get the Attribute store of DevProxy. +// A device MFT loaded will not pass through the devproxy attribute store, but it will pass +// the device MFT attributes. This should be similar to the singular DevProxy attribute +// which the MFT0 providers can use to synchronize across various MFT0's +// + +STDMETHODIMP CMultipinMft::GetAttributes( + _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes + ) +{ + HRESULT hr = S_OK; + + DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG); + + *ppAttributes = nullptr; + + if (m_spAttributes != nullptr) + { + m_spAttributes.CopyTo(ppAttributes); + } + else + { + hr = E_OUTOFMEMORY; + } + +done: + return hr; +} +#endif + + + + +// +//HELPER FUNCTIONS +// + +STDMETHODIMP_(CBasePin*) CMultipinMft::GetInPin( + _In_ DWORD dwStreamId + ) +{ + CInPin *inPin = NULL; + for (DWORD dwIndex = 0, dwSize = (DWORD)m_InPins.size(); dwIndex < dwSize; dwIndex++) + { + inPin = (CInPin *)m_InPins[dwIndex]; + if (dwStreamId == inPin->streamId()) + { + break; + } + inPin = NULL; + } + return inPin; +} + +STDMETHODIMP_(CBasePin*) CMultipinMft::GetOutPin( + _In_ DWORD dwStreamId + ) +{ + COutPin *outPin = NULL; + + for ( DWORD dwIndex = 0, dwSize = (DWORD) m_OutPins.size(); dwIndex < dwSize; dwIndex++ ) + { + outPin = ( COutPin * )m_OutPins[ dwIndex ]; + + if ( dwStreamId == outPin->streamId() ) + { + break; + } + + outPin = NULL; + } + + return outPin; +} + +/*++ +Description: +This is a critical function which changes the state on an output pin +This should be called under the control lock of the DT. +Here the +--*/ +STDMETHODIMP CMultipinMft::ChangeMediaTypeEx( + _In_ ULONG pinId, + _In_opt_ IMFMediaType *pMediaType, + _In_ DeviceStreamState reqState + ) +{ + HRESULT hr = S_OK; + DeviceStreamState oldOutPinState; + DeviceStreamState newOutStreamState; + ComPtr<IMFMediaType> pFullType = nullptr; + + COutPin *poPin = static_cast<COutPin*>( GetOutPin(pinId) ); + + MMFTMMAPITERATOR inputPinPos; + + DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG ); + // + //Check if the media type requested is a supported type + // + if ( pMediaType ) + { + if ( !poPin->IsMediaTypeSupported( pMediaType, &pFullType ) ) + { + DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done); + } + } + // + //First step disable the output pin. store the old state + // + oldOutPinState = poPin->SetState( DeviceStreamState_Disabled ); + + (void)poPin->FlushQueues(); + + newOutStreamState = pinStateTransition[oldOutPinState][reqState]; //New state needed + + // + //Go through the output pins' maps that has the conencted input pin to the output pin + // + inputPinPos = m_outputPinMap.equal_range( pinId ); + + for (std::multimap<int, int>::iterator piterator = inputPinPos.first; piterator != inputPinPos.second;piterator++) + { + // + //Get the output pins connected to the input pin. The input pin map consists of the output pins connected + // + ULONG connectedInputPin = (*piterator).second; + BOOL isAnyConnectedOutPinActive = false; + BOOL isAnyConnectedOutPinPaused = false; + BOOL isAnyConnectedOutPinRunning = false; + BOOL doWeWaitForSetInput = false; + DeviceStreamState oldInputStreamState; + MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal; + ComPtr<IMFMediaType> pInputMediaType = nullptr; + CInPin *pconnectedInPin = (CInPin*)GetInPin( connectedInputPin ); + oldInputStreamState = pconnectedInPin->SetState( DeviceStreamState_Disabled ); + DeviceStreamState newRequestedInPinState = pinStateTransition[oldInputStreamState][newOutStreamState]; + + if (pFullType) + { + pconnectedInPin->getMediaType( &pInputMediaType ); + } + + // + // Check if we need an XVP to be inserted between this input and output pins. + // + CompareMediaTypesForXVP( pInputMediaType.Get(), pFullType.Get(), &operation ); + DMFTCHECKHR_GOTO( GetConnectOutPinStatus( connectedInputPin, + pinId, // pinId = stream which should be excluded from the search. This function searches if + &isAnyConnectedOutPinPaused, // there are any other output pins connected other than the ouput pin (on which the change media type is requested) + &isAnyConnectedOutPinRunning, //, which is streaming, paused. This way if the output pin is requested to go to Pause, Stop and if any of the + &isAnyConnectedOutPinActive ),done ); //other connected output pins are active, then input it not deactivated + + // + //Check if we are asked to go to an active state + //Check for the new media type. if + // + if ( !IsPinStateInActive( newRequestedInPinState ) ) + { + // + //We are being told to go active + //We will request a change in input stream state. + // + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going active IN: %d OUT: %d ", this, connectedInputPin, pinId ); + doWeWaitForSetInput = true; + if ( !pFullType ) + { + DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done); + } + if ( (! pInputMediaType ) || ( operation == DeviceMftTransformXVPDisruptiveIn ) ) + { + pInputMediaType = pFullType; + } + if ( newRequestedInPinState == DeviceStreamState_Pause && isAnyConnectedOutPinRunning ) + { + newRequestedInPinState = DeviceStreamState_Run; + } + } + else + { + // + //We have been requested to go inactive + // + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going Inactive IN: %d OUT: %d ", this, connectedInputPin, pinId ); + + if ( operation == DeviceMftTransformXVPDisruptiveIn ) + { + // + //Only where we recieve a disruptive media type change and a media type along with it, which is unlikely!! + // + pInputMediaType = pFullType; + doWeWaitForSetInput = true; + } + if ( isAnyConnectedOutPinActive ) + { + newRequestedInPinState = ( isAnyConnectedOutPinRunning ) ? DeviceStreamState_Run : DeviceStreamState_Pause; + } + else + { + //Switch over to the new media type.. + pInputMediaType = pFullType; + if ( !IsPinStateInActive( oldInputStreamState ) ) + { + //It was originall active.. now going down + doWeWaitForSetInput = true; + } + } + } + + // + // This will happen if we need a change in Input media type, We will send an event + // METransformInputStreamStateChanged to the Device transform manager. This will result + // in the Device Transform manager calling us back in getprefferedinputstate where + // we will give it back the state of the input and the media type to be set. + // All this happens when we are holding a lock here in Change output media type. Hence during the + // input media type change we don't hold a lock. THE DTM takes care not to send you any more media + // type change operations that can cause a deadlock. + // + + if ( doWeWaitForSetInput ) + { + pconnectedInPin->setPreferredMediaType( pInputMediaType.Get() ); + pconnectedInPin->setPreferredStreamState( newRequestedInPinState ); + SendEventToManager( METransformInputStreamStateChanged, GUID_NULL, pconnectedInPin->streamId() ); + // + //The media type will be set on the input pin by the time we return from the wait + // + DMFTCHECKHR_GOTO( pconnectedInPin->WaitForSetInputPinMediaChange(), done ); + } + else + { + pconnectedInPin->SetState( oldInputStreamState ); + pconnectedInPin->setMediaType( pInputMediaType.Get() ); + } + + //Now the input type is all set.. + pInputMediaType = nullptr; + (VOID)pconnectedInPin->getMediaType( &pInputMediaType ); + // + //Now propogate the media type change to the output pins + // + MMFTMMAPITERATOR outputPinPos = m_inputPinMap.equal_range(pconnectedInPin->streamId()); + for ( std::multimap<int, int>::iterator poutPinsIterator = outputPinPos.first; + poutPinsIterator != outputPinPos.second; + poutPinsIterator++ ) + { + ComPtr<IMFMediaType> pOutMediatype = nullptr; + DeviceStreamState outPinState; + ULONG connectedoutPin = (*poutPinsIterator).second; + COutPin* pIoPin = static_cast<COutPin*>( GetOutPin ( connectedoutPin ) ); + + (VOID)pIoPin->getMediaType( &pOutMediatype ); + outPinState = pIoPin->GetState(); + + if ( pIoPin->streamId() != pinId) + { + // + //This is the pin other than the output pin where the original change media type was recieved. + // + + if ( pInputMediaType != nullptr && pOutMediatype != nullptr ) + { + DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(), + pOutMediatype.Get(), + outPinState ),done); + } + } + else + { + // + //Change the media type of the requested output pin + // + DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(), pFullType.Get(), newOutStreamState), done); + //Also signal to the manager that a stream state change has happened + SendEventToManager( MEUnknown, MEDeviceStreamCreated, pIoPin->streamId()); + // + //Set the First Sample Flag. this will get reset when the first sample comes in. We will signal the discontinuity + //when we get a Processoutput from the Device Transform Manager + // + pIoPin->SetFirstSample(TRUE); + + } + pOutMediatype = nullptr; + } + + } + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::SendEventToManager( + _In_ MediaEventType eventType, + _In_ REFGUID pGuid, + _In_ UINT32 context + ) + /*++ + Description: + Used to send the event to DTM. + --*/ + { + HRESULT hr = S_OK; + ComPtr<IMFMediaEvent> pEvent = nullptr; + + DMFTCHECKHR_GOTO(MFCreateMediaEvent(eventType, pGuid, S_OK, NULL, &pEvent ),done); + DMFTCHECKHR_GOTO(pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, (ULONG)context),done); + DMFTCHECKHR_GOTO(QueueEvent(pEvent.Get()),done); + done: + + return hr; + } + + +STDMETHODIMP CMultipinMft::GetConnectOutPinStatus( + _In_ ULONG ulPinId, + _In_ ULONG ulOutPinId, + _Inout_ PBOOL pAnyInPauseState, + _Inout_ PBOOL pAnyInRunState, + _Inout_ PBOOL pAnyActive + ) + /*++ + Description: + + This function gets the statuses of the output pins other than the one specified + The arguments are as follows + ulPinId: The input pins which are connected to the ouput pin ulOutPinId + ulOutPinId: The pin to be excluded from the check i.e. the input pin from which the request is usually sent. + --*/ +{ + HRESULT hr = S_OK; + MMFTMMAPITERATOR outputPinPos; + CInPin *pconnectedInPin = (CInPin*)GetInPin(ulPinId); + DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_INVALIDARG ); + + outputPinPos = m_inputPinMap.equal_range( pconnectedInPin->streamId() ); + DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_FAIL ); + + *pAnyActive = *pAnyInPauseState = *pAnyInRunState = false; + + for ( std::multimap<int, int>::iterator poutPosIterator = outputPinPos.first; + poutPosIterator != outputPinPos.second; + poutPosIterator++ ) + { + ULONG connectedoutPin = (*poutPosIterator).second; + COutPin* pconnectedOutPin = ( COutPin * )GetOutPin( connectedoutPin ); + + if (pconnectedOutPin->streamId() != ulOutPinId) + { + //This is excluding the outpin which requested pin state change + *pAnyActive |= !IsPinStateInActive( pconnectedOutPin->GetState() ); + *pAnyInPauseState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Pause ); + *pAnyInRunState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Run ); + } + + } + done: + return S_OK; +} + + +/*++ +Description: +This function connects the input and output pins. +Any media type filtering can happen here +--*/ +STDMETHODIMP CMultipinMft::BridgeInputPinOutputPin( + _In_ CInPin* piPin, + _In_ COutPin* poPin + ) +{ + HRESULT hr = S_OK; + ULONG ulIndex = 0; + ComPtr<IMFMediaType> pMediaType = nullptr; + + DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG ); + DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG ); + // + // Copy over the media types from input pin to output pin. Since there is no + // decoder support, only the uncompressed media types are inserted. Please make + // sure any pin advertised supports at least one media type. The pipeline doesn't + // like pins with no media types + // + while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, &pMediaType ))) + { + GUID subType = GUID_NULL; + DMFTCHECKHR_GOTO( pMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done ); + + if ( IsKnownUncompressedVideoType( subType ) ) + { + DMFTCHECKHR_GOTO( poPin->AddMediaType(NULL, pMediaType.Get() ), done ); + } + + pMediaType = nullptr; + } + // + //Add the Input Pin to the output Pin + // + DMFTCHECKHR_GOTO(poPin->AddPin(piPin->streamId()), done); + hr = ExceptionBoundary([&](){ + // + //Add the output pin to the input pin. + // + piPin->ConnectPin(poPin); + }); + DMFTCHECKHR_GOTO(hr, done); + // + //Create the map. This will be useful when we have to decide the state transitions of the pins + // + m_inputPinMap.insert ( std::pair< int,int >( piPin->streamId(), poPin->streamId()) ); + m_outputPinMap.insert ( std::pair< int, int >( poPin->streamId(), piPin->streamId()) ); +done: + // + //Failed adding media types + // + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + } + return hr; +} + + +// +//The below routines are used to implement the extended controls needed to implement the photo sequence +//The photo sequence is enabled for cameras with no independent image pins +//The extended controls needed to enable photo sequence are discussed in detail in the photo sequence document +// + +/*++ +Extended Photo Mode handler is the extended property handler dealing with the photosequence and single mode capabilities of the camera +--*/ +STDMETHODIMP CMultipinMft::ExtendedPhotoModeHandler( +_In_ PKSPROPERTY Property, +_In_ ULONG ulPropertyLength, +_In_ LPVOID pData, +_In_ ULONG ulOutputBufferLength, +_Inout_ PULONG pulBytesReturned +) + +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER( ulPropertyLength ); + + if ( Property->Flags & KSPROPERTY_TYPE_SET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ); + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done ); + } + else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) ) + { + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done ); + } + else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) ) + { + PBYTE pPayload = ( PBYTE )pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload ); + // + //Use the below structure to make changes to the Property and thus affect the configuration + //PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_PHOTOMODE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER)); + // + m_FilterInPhotoSequence = pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE; + DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE), done); + } + else + { + DMFTCHECKHR_GOTO(E_INVALIDARG, done); + } + } + else if ( Property->Flags & KSPROPERTY_TYPE_GET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ); + hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA); + } + else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) ) + { + PBYTE pPayload = (PBYTE)pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload ); + PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_PHOTOMODE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) ); + + pExtendedHeader->Capability = ( KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE ); + pExtendedHeader->Flags = ( m_FilterInPhotoSequence ) ? KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE : KSCAMERA_EXTENDEDPROP_PHOTOMODE_NORMAL; + pExtendedHeader->Result = 0; + pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ); + pExtendedHeader->Version = 1; + + pExtendedValue->MaxHistoryFrames = 10; + pExtendedValue->RequestedHistoryFrames = 0 ; + pExtendedValue->SubMode = 0 ; + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ); + } + else + { + DMFTCHECKHR_GOTO( E_INVALIDARG, done ); + } + } + +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + + return hr; +} + +/*++ +The Extended Max Frame rate is self explanatory +--*/ +STDMETHODIMP CMultipinMft::ExtendedPhotoMaxFrameRate( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ) + +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER( ulPropertyLength ); + + if ( Property->Flags & KSPROPERTY_TYPE_SET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE)) + { + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE)) + { + // + //This is for setting the Max frame rate.. + // + //PBYTE pPayload = (PBYTE)pData; + //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload); + //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER)); + // + DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE), done); + } + else + { + DMFTCHECKHR_GOTO(E_INVALIDARG, done); + } + } + else if ( Property->Flags & KSPROPERTY_TYPE_GET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + hr = HRESULT_FROM_WIN32( ERROR_MORE_DATA ); + } + else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE )) + { + PBYTE pPayload = ( PBYTE )pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload ); + PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) ); + pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL; + pExtendedHeader->Flags = 0; + pExtendedHeader->Result = 0; + pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE); + pExtendedHeader->Version = 1; + pExtendedValue->Value.ratio.HighPart = 30; + pExtendedValue->Value.ratio.LowPart = 1; + *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE); + } + else + { + DMFTCHECKHR_GOTO(E_INVALIDARG, done); + } + } + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + + return hr; +} + + +STDMETHODIMP CMultipinMft::MaxVidFPS_PhotoResHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ) +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER( ulPropertyLength ); + if ( Property->Flags & KSPROPERTY_TYPE_SET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ) ) + { + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done ); + } + else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES )) + { + PBYTE pPayload = (PBYTE)pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload ); + // + //Use the extended value to make changes to the property.. refer documentation + //PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER)); + // + pExtendedHeader->Capability = 0; + pExtendedHeader->Flags = 0; + pExtendedHeader->Result = 0; + pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + pExtendedHeader->Version = 1; + + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ); + } + + else + { + hr = E_INVALIDARG; + } + } + else if (Property->Flags & KSPROPERTY_TYPE_GET) + { + if (ulOutputBufferLength == 0) + { + *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES)) + { + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES)) + { + PBYTE pPayload = (PBYTE)pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )(pPayload ); + PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER)); + pExtendedHeader->Capability = 0; + pExtendedHeader->Flags = 0; + pExtendedHeader->Result = 0; + pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(PKSCAMERA_MAXVIDEOFPS_FORPHOTORES); + pExtendedHeader->Version = 1; + + pExtendedValue->PreviewFPSNum = 30; + pExtendedValue->PreviewFPSDenom = 1; + pExtendedValue->CaptureFPSNum = 30; + pExtendedValue->CaptureFPSDenom = 1; + pExtendedValue->PhotoResHeight = 240; + pExtendedValue->PhotoResWidth = 320; + + *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES); + } + else + { + hr = E_INVALIDARG; + } + } +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +STDMETHODIMP CMultipinMft::QPCTimeHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ) +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER( ulPropertyLength ); + + if ( Property->Flags & KSPROPERTY_TYPE_SET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done ); + } + else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) ) + { + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) ) + { + //PBYTE pPayload = (PBYTE)pData; + // + //If the payload is to be used.. use the below structures + // + //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload); + //Use the extended value to make changes to the property.. refer documentation + //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER)); + // + *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + } + else + { + hr = E_INVALIDARG; + } + } + else if ( Property->Flags & KSPROPERTY_TYPE_GET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) ) + { + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done ); + } + else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) ) + { + PBYTE pPayload = (PBYTE)pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload ); + PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) ); + pExtendedHeader->Capability = 0; + pExtendedHeader->Flags = KSPROPERTY_CAMERA_PHOTOTRIGGERTIME_SET; + pExtendedHeader->Result = 0; + pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + pExtendedHeader->Version = 1; + pExtendedValue->Value.ull = 0; + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + } + else + { + hr = E_INVALIDARG; + } + } +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + +STDMETHODIMP CMultipinMft::PhotoFrameRateHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ) +{ + HRESULT hr = S_OK; + + UNREFERENCED_PARAMETER( ulPropertyLength ); + if ( Property->Flags & KSPROPERTY_TYPE_SET ) + { + // + //This is a read only property!!! + // + hr = E_INVALIDARG; + } + else if ( Property->Flags & KSPROPERTY_TYPE_GET ) + { + if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE )) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done ); + } + PBYTE pPayload = (PBYTE)pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload ); + PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) ); + pExtendedHeader->Capability = 0; + pExtendedHeader->Flags = 0; + pExtendedHeader->Result = 0; + pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + pExtendedHeader->Version = 1; + pExtendedValue->Value.ratio.HighPart = 30; + pExtendedValue->Value.ratio.LowPart = 1; + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + + } +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + + +STDMETHODIMP CMultipinMft::WarmStartHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ) +{ + + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER( ulPropertyLength ); + *pulBytesReturned = 0; + + if ( Property->Flags & KSPROPERTY_TYPE_SET ) + { + if ( ulOutputBufferLength == 0 ) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done); + } + else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE )) + { + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done); + } + else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE )) + { + PBYTE pPayload = ( PBYTE )pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )pPayload; + // + //Use the extended value to make changes to the property.. refer documentation + //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER)); + // + if ( pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED ) + { + m_filterInWarmStart = true; + } + else + { + m_filterInWarmStart = false; + } + + *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART); + } + else + { + hr = S_OK; + } + } + else if (Property->Flags & KSPROPERTY_TYPE_GET) + { + if (ulOutputBufferLength == 0) + { + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE )) + { + DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done ); + } + else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE )) + { + PBYTE pPayload = ( PBYTE )pData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload ); + // + //Use the extended value to make changes to the property.. refer documentation + //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER)); + // + pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED; + pExtendedHeader->Flags = 0; + + if (m_filterInWarmStart) + { + pExtendedHeader->Flags |= KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED; + } + + pExtendedHeader->Result = 0; + pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + pExtendedHeader->Version = 1; + *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ); + hr = S_OK; + } + else + { + hr = S_OK; + } + } +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + + +// +// IMFShutdown interface functions +// + +/*++ +Description: +Implements the Shutdown from IMFShutdown +--*/ +STDMETHODIMP CMultipinMft::Shutdown( + void + ) +{ + CAutoLock Lock(m_critSec); + (VOID) m_eventHandler.Clear(); + return ShutdownEventGenerator(); +} + +// +// Static method to create an instance of the MFT. +// +HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT) +{ + HRESULT hr = S_OK; + CMultipinMft *pMFT = NULL; + DMFTCHECKNULL_GOTO(ppMFT, done, E_POINTER); + pMFT = new (std::nothrow) CMultipinMft(); + DMFTCHECKNULL_GOTO(pMFT, done, E_OUTOFMEMORY); + + DMFTCHECKHR_GOTO(pMFT->QueryInterface(iid, ppMFT), done); + +done: + if (FAILED(hr)) + { + SAFERELEASE(pMFT); + } + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + + + + +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) +/* +Desciption: +This function will be called by the preview pin to execute the photo confirmation stored with the +MFT. +*/ + +STDMETHODIMP CMultipinMft::ProcessCapturePhotoConfirmationCallBack( + _In_ IMFMediaType* pMediaType, + _In_ IMFSample* pSample + ) +{ + // + //PhotoConfirmation Implementation + //Note this function doesn't scan the metadata as the pipeline does to find out which buffer is the photoconfirmation buffer + //The pipeline treats the preview buffer as the photo confirmation buffer and the driver marks the metadata on the buffer as being so. + //This example treats every buffer coming on the pin as the confirmation buffer. + // + + HRESULT hr = S_OK; + ComPtr<IMFMediaType> spMediaType = nullptr; + LONGLONG timeStamp = 0; + + DMFTCHECKHR_GOTO(MFCreateMediaType(&spMediaType), done); + DMFTCHECKHR_GOTO(pMediaType->CopyAllItems(spMediaType.Get()), done); + + DMFTCHECKHR_GOTO(pSample->SetUnknown(MFSourceReader_SampleAttribute_MediaType_priv, spMediaType.Get()), done); + + DMFTCHECKHR_GOTO(pSample->GetSampleTime(&timeStamp), done); + DMFTCHECKHR_GOTO(pSample->SetUINT64(MFSampleExtension_DeviceReferenceSystemTime, timeStamp), done); + + if (m_spPhotoConfirmationCallback) + { + + // + //We are directly sending the photo sample over to the consumers of the photoconfirmation interface. + // + ComPtr<IMFAsyncResult> spResult; + DMFTCHECKHR_GOTO(MFCreateAsyncResult(pSample, m_spPhotoConfirmationCallback.Get(), NULL, &spResult), done); + DMFTCHECKHR_GOTO(MFInvokeCallback(spResult.Get()), done); + } +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +#endif + +// +// Only worry about this if you have customs pins defined in the driver +// + +STDMETHODIMP CMultipinMft::SetStreamingStateCustomPins( + DeviceStreamState State + ) +{ + HRESULT hr = S_OK; + + if ( m_CustomPinCount > 0 ) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin State changing to %d", State); + + for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++) + { + BOOL isCustom = false; + CInPin* pInPin = static_cast<CInPin*>(m_InPins[ulIndex]); + + if ( SUCCEEDED( CheckCustomPin(pInPin, &isCustom) ) + && ( isCustom ) ) + { + pInPin->SetState(State); + } + } + } + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} diff --git a/AVStream/sampledevicemft/multipinmft.h b/AVStream/sampledevicemft/multipinmft.h new file mode 100644 index 00000000..244a47be --- /dev/null +++ b/AVStream/sampledevicemft/multipinmft.h @@ -0,0 +1,477 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#pragma once + +#include "common.h" +#include "mftpeventgenerator.h" +#include "basepin.h" +#include "custompin.h" +#include "multipinmfthelpers.h" + +// +// The Below GUID is needed to transfer photoconfirmation sample successfully in the pipeline +// It is used to propagate the mediatype of the sample to the pipeline which will consume the sample +// This attribute is known to the OS, but not publicly defined. +// + +DEFINE_GUID(MFSourceReader_SampleAttribute_MediaType_priv, + 0x0ea5c1e8, 0x9845, 0x41e0, 0xa2, 0x43, 0x72, 0x32, 0x07, 0xfc, 0x78, 0x1f); + + +interface IDirect3DDeviceManager9; + +// +// Forward declarations +// +class CMFAttributes; + +// +// CMultipinMft class: +// Implements a device proxy MFT. +// +class CMultipinMft : + public IMFDeviceTransform +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + , public IMFTransform +#endif + , public IMFShutdown + , public CMediaEventGenerator + , public IMFRealTimeClientEx + , public IKsControl +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) + , public IMFCapturePhotoConfirmation + , public IMFGetService +#endif +{ +public: + CMultipinMft( + void ); + + virtual ~CMultipinMft(); + + // + // IUnknown + // + STDMETHOD_(ULONG, AddRef)( + void ); + + STDMETHOD_(ULONG, Release)( + void ); + + STDMETHOD(QueryInterface)( + _In_ REFIID iid, + _COM_Outptr_ void** ppv); + + + // + // IMFDeviceTransform functions + // + STDMETHOD(GetStreamCount)( + _Inout_ DWORD *pdwInputStreams, + _Inout_ DWORD *pdwOutputStreams); + + + STDMETHOD(GetStreamIDs)( + _In_ DWORD dwInputIDArraySize, + _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs, + _In_ DWORD dwOutputIDArraySize, + _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)), + _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs + ); + + STDMETHOD(GetInputStreamAttributes)( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes); + + STDMETHOD(GetOutputStreamAttributes)( + _In_ DWORD dwOutputStreamID, + _Out_ IMFAttributes** ppAttributes); + + STDMETHOD(GetInputAvailableType)( + _In_ DWORD dwInputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppType); + + STDMETHOD(GetOutputAvailableType)( + _In_ DWORD dwOutputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType); + + STDMETHOD(GetInputCurrentType)( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType); + + STDMETHOD(GetOutputCurrentType)( + _In_ DWORD dwOutputStreamID, + _Out_ IMFMediaType** ppMediaType); + + STDMETHOD(ProcessMessage)( + _In_ MFT_MESSAGE_TYPE eMessage, + _In_ ULONG_PTR ulParam ); + + STDMETHOD(ProcessEvent)( + _In_ DWORD dwInputStreamID, + _In_ IMFMediaEvent *pEvent); + + + STDMETHOD(ProcessInput)( + _In_ DWORD dwInputStreamID, + _In_ IMFSample* pSample, + _In_ DWORD dwFlags ); + + STDMETHOD(ProcessOutput)( + _In_ DWORD dwFlags, + _In_ DWORD cOutputBufferCount, + _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, + _Out_ DWORD *pdwStatus ); + + // + // IMFRealTimeClientEx + // + STDMETHOD(RegisterThreadsEx)( + _Inout_ DWORD* pdwTaskIndex, + _In_ LPCWSTR wszClassName, + _In_ LONG lBasePriority ) + { + UNREFERENCED_PARAMETER(pdwTaskIndex); + UNREFERENCED_PARAMETER(wszClassName); + UNREFERENCED_PARAMETER(lBasePriority); + return S_OK; + } + + STDMETHOD(UnregisterThreads)() + { + return S_OK; + } + + STDMETHOD(SetWorkQueueEx)( + _In_ DWORD dwWorkQueueId, + _In_ LONG lWorkItemBasePriority ); + + // + // IMFShutdown + // + STDMETHOD(Shutdown)( + void ); + + STDMETHOD(GetShutdownStatus)( + MFSHUTDOWN_STATUS *pStatus) + { + UNREFERENCED_PARAMETER(pStatus); + return(m_eShutdownStatus); + }; + + // + // IMFDeviceTransform function declarations + // + STDMETHODIMP InitializeTransform( + _In_ IMFAttributes *pAttributes ); + + _Requires_no_locks_held_ + STDMETHODIMP SetInputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags ); + + STDMETHODIMP GetInputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value ); + + STDMETHODIMP SetOutputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags ); + + STDMETHODIMP GetOutputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value ); + + STDMETHODIMP GetInputStreamPreferredState( + _In_ DWORD dwStreamID, + _Inout_ DeviceStreamState *value, + _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType ); + + STDMETHODIMP FlushInputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags ); + + STDMETHODIMP FlushOutputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags ); + + STDMETHODIMP_(VOID) FlushAllStreams( + VOID + ); + + // + //IKSControl Inferface function declarations + // + STDMETHOD(KsEvent)( + _In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + STDMETHOD(KsProperty)( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + STDMETHOD(KsMethod)( + _In_reads_bytes_(ulPropertyLength) PKSMETHOD pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) + // + // The Below functions are needed for photoconfirmation + // + // + STDMETHOD(GetService)( + __in REFGUID guidService, + __in REFIID riid, + __deref_out LPVOID* ppvObject + ); + // + //IMFCapturePhotoConfirmation Inferface function declarations + // + STDMETHOD(SetPhotoConfirmationCallback)( + _In_ IMFAsyncCallback* pNotificationCallback + ); + STDMETHOD(SetPixelFormat)( + _In_ GUID subtype + ); + STDMETHOD(GetPixelFormat)( + _Out_ GUID* subtype + ); + + __inline BOOL IsPhotoConfirmationEnabled() + { + return (m_spPhotoConfirmationCallback != nullptr); + } + + STDMETHODIMP ProcessCapturePhotoConfirmationCallBack( + _In_ IMFMediaType* pMediaType, + _In_ IMFSample* pSample + ); + + __inline VOID SetPhotoConfirmationCallBack(_In_ IMFAsyncCallback *Callback) + { + m_spPhotoConfirmationCallback = Callback; + } + +#endif + + static STDMETHODIMP CreateInstance( + REFIID iid, void **ppMFT); + + // + //Below functions are used by the pins to enquire the state of the Filter for Photo sequence. + //A Trigger is a ksproperty sent to the filter. + // + + __inline VOID setPhotoTriggerSent(_In_ BOOL Set) + { + m_PhotoTriggerSent = Set; + } + __inline BOOL isPhotoTriggerSent() + { + return m_PhotoTriggerSent; + } + + __inline BOOL isPhotoModePhotoSequence() + { + return m_PhotoModeIsPhotoSequence; + } + __inline BOOL filterHasIndependentPin() + { + return m_filterHasIndependentPin; + } + + // + //Will be used from Pins to get the D3D manager once set!!! + // + __inline STDMETHODIMP_(VOID) GetD3DDeviceManager( + IUnknown** ppDeviceManagerUnk + ) + { + m_spDeviceManagerUnk.CopyTo( ppDeviceManagerUnk ); + } + + STDMETHODIMP SendEventToManager( + _In_ MediaEventType, + _In_ REFGUID, + _In_ UINT32 + ); + +protected: + + // + //Helper functions + // + + STDMETHODIMP SetStreamingStateCustomPins( + _In_ DeviceStreamState + ); + + STDMETHODIMP_(CBasePin*) GetInPin( + _In_ DWORD dwStreamID + ); + + STDMETHODIMP_(CBasePin*) GetOutPin( + _In_ DWORD dwStreamID + ); + + STDMETHODIMP ChangeMediaTypeEx( + _In_ ULONG pinId, + _In_opt_ IMFMediaType *pMediaType, + _In_ DeviceStreamState newState + ); + + STDMETHODIMP GetConnectOutPinStatus( + _In_ ULONG ulPinId, + _In_ ULONG ulOutPin, + _Inout_ PBOOL pAnyInPauseState, + _Inout_ PBOOL pAnyInRunState, + _Inout_ PBOOL pAnyActive + ); + STDMETHODIMP BridgeInputPinOutputPin( + _In_ CInPin* pInPin, + _In_ COutPin* pOutPin); + + // + //Implementing the below to simulate a photosequence + //This is just to show that photosequence can be achieved purely in + //the user mode with the device MFT.. + // + STDMETHODIMP ExtendedPhotoModeHandler( + _In_ PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pvPropertyData, + _In_ ULONG ulDataLength, + _Inout_ PULONG pulBytesReturned + ); + + STDMETHODIMP ExtendedPhotoMaxFrameRate( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ); + STDMETHODIMP MaxVidFPS_PhotoResHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ); + STDMETHODIMP QPCTimeHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ); + STDMETHODIMP PhotoFrameRateHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ); + STDMETHODIMP CMultipinMft::WarmStartHandler( + _In_ PKSPROPERTY Property, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pData, + _In_ ULONG ulOutputBufferLength, + _Inout_ PULONG pulBytesReturned + ); +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + STDMETHODIMP CMultipinMft::GetAttributes( + _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes + ); +#endif + +#if (defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)) + _DEFINE_DEVICEMFT_MFT0HELPER_IMPL__ +#endif + + + // + //Inline functions + // + + __inline IMFTransform* Parent() + { + return m_spSourceTransform.Get(); + } + + __inline VOID SetStreamingState(DeviceStreamState state) + { + InterlockedExchange((LONG*)&m_StreamingState, state); + } + __inline DeviceStreamState GetStreamingState() + { + return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_StreamingState, m_StreamingState, m_StreamingState); + } + __inline BOOL IsStreaming() + { + return (InterlockedCompareExchange((LONG*)&m_StreamingState, DeviceStreamState_Run, DeviceStreamState_Run) == DeviceStreamState_Run); + } + +private: + ULONG m_InputPinCount; + ULONG m_OutputPinCount; + ULONG m_CustomPinCount; + DeviceStreamState m_StreamingState; + CBasePinArray m_OutPins; + CBasePinArray m_InPins; + BOOL m_PhotoTriggerSent; + BOOL m_PhotoModeIsPhotoSequence; // used to store if the filter is in photo sequence or not + BOOL m_FilterInPhotoSequence; // This applies for the filter, which is in a photo sequence or not. This is set by the Extended property handler + BOOL m_filterHasIndependentPin; // If any of the input pins from the source transform expose an independent photo pin then we will not simluate photoseqeunce + BOOL m_filterInWarmStart; // Used to store if the filter is in warm start or not! + long m_nRefCount; // Reference count + CCritSec m_critSec; // Control lock.. taken only durign state change operations + ComPtr <IUnknown> m_spDeviceManagerUnk; // D3D Manager set, when MFT_MESSAGE_SET_D3D_MANAGER is called through ProcessMessage + ComPtr<IMFTransform> m_spSourceTransform; // The sources transform + MFSHUTDOWN_STATUS m_eShutdownStatus; + DWORD m_dwWorkQueueId; + LONG m_lWorkQueuePriority; + UINT32 m_punValue; + ComPtr<IKsControl> m_spIkscontrol; + ComPtr<IMFAttributes> m_spAttributes; + + multimap<int, int> m_inputPinMap; // How input pins are connected to output pins o-><0..inpins> + multimap<int, int> m_outputPinMap; // How output pins are connected to input pins i-><0..outpins> + CDMFTEventHandler m_eventHandler; + +#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION) + ComPtr<IMFAsyncCallback> m_spPhotoConfirmationCallback; //Photo Confirmation related definitions + GUID m_guidPhotoConfirmationSubtype; +#endif + +}; + + + +inline HRESULT MFT_CreateInstance(REFIID riid, void **ppv) +{ + return CMultipinMft::CreateInstance(riid, ppv); +} + + diff --git a/AVStream/sampledevicemft/multipinmft.vcxproj b/AVStream/sampledevicemft/multipinmft.vcxproj new file mode 100644 index 00000000..31107772 --- /dev/null +++ b/AVStream/sampledevicemft/multipinmft.vcxproj @@ -0,0 +1,263 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{E77657CD-A270-49E1-823A-8A14FF8596C8}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <SupportsPackaging>false</SupportsPackaging> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{D6CB33D6-DEF2-497E-A72D-6E6E29C67F48}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="mftpeventgenerator.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="multipinmft.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="basepin.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="multipinmfthelpers.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="multipinmftutils.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="custompin.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="dllmain.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>multipinmft</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>multipinmft</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>multipinmft</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>multipinmft</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>Source.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>Source.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>Source.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>Source.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="stdafxsrc.cpp"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/AVStream/sampledevicemft/multipinmft.vcxproj.Filters b/AVStream/sampledevicemft/multipinmft.vcxproj.Filters new file mode 100644 index 00000000..e06f675d --- /dev/null +++ b/AVStream/sampledevicemft/multipinmft.vcxproj.Filters @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{39379DB7-5CE0-407A-A6D4-F2F23BB3BF3C}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{05E63691-6953-4F79-BEC2-1CF881B618BA}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{B10F4398-9892-4AA8-8653-E5A7F4726726}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="basepin.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="custompin.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllmain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mftpeventgenerator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="multipinmft.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="multipinmfthelpers.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="multipinmftutils.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="stdafxsrc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="Source.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/AVStream/sampledevicemft/multipinmfthelpers.cpp b/AVStream/sampledevicemft/multipinmfthelpers.cpp new file mode 100644 index 00000000..078ca337 --- /dev/null +++ b/AVStream/sampledevicemft/multipinmfthelpers.cpp @@ -0,0 +1,988 @@ +#include "stdafx.h" +#include "common.h" +#include "multipinmfthelpers.h" +#include "multipinmft.h" +#include "basepin.h" +#include <wincodec.h> + +#ifdef MF_WPP +#include "multipinmfthelpers.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif +class CMediaTypePrinter; +// +//Queue implementation +// + +CPinQueue::CPinQueue( _In_ DWORD _InpinId ) +: m_teer(0), + m_discotinuity(0), + m_sampleCount(0), + m_dwInPinId(_InpinId) + /* + Description + _InpinId is the input pin Id to which this queue corresponds + */ +{ +} +CPinQueue::~CPinQueue( ) +{ +} + +/*++ +Description: + Insert sample into the list once we reach the open queue +--*/ +STDMETHODIMP_(VOID) CPinQueue::InsertInternal( _In_ IMFSample *pSample ) +{ + pSample->AddRef(); + HRESULT hr = ExceptionBoundary([&]() + { + m_sampleList.push_back(pSample); + }); + + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + SAFE_RELEASE(pSample); + } +} + +STDMETHODIMP_(BOOL) CPinQueue::Insert( _In_ IMFSample *pSample ) +// +//m_teer is the wraptee.. this could be a null tee which is a passthrough, an xvp tee, which inserts an xvp into the queue +// +{ + return SUCCEEDED( m_teer->PassThrough( pSample, this ) ); +} + + +/*++ +Description: + This extracts the first sample from the queue. called from Pin's ProcessOutput +--*/ + +STDMETHODIMP_(BOOL) CPinQueue::Remove( _Outptr_result_maybenull_ IMFSample **ppSample) +{ + HRESULT hr = S_OK; + DMFTCHECKNULL_GOTO( ppSample, done,E_INVALIDARG ); + *ppSample = nullptr; + + if ( !m_sampleList.empty() ) + { + *ppSample = m_sampleList.front(); + } + + DMFTCHECKNULL_GOTO( *ppSample, done, MF_E_TRANSFORM_NEED_MORE_INPUT ); + + (*ppSample)->Release( ); + + m_sampleList.erase( m_sampleList.begin() ); +done: + return SUCCEEDED( hr ) ? TRUE : FALSE; +} + +/*++ +Description: + Empties the Queue. used by the flush +--*/ +VOID CPinQueue::Clear( ) +{ + IMFSample* pSample = nullptr; + while ( !Empty() ) + { + Remove( &pSample ); + SAFE_RELEASE( pSample ); + } +} + +/*++ +Description: + RecreateTee creates the underlying Tees in the queue. It accepts the input media type + which is the media type set on the input pin and the output mediatype, which (duh) is the + media type on the output pin + It also takes an IUnknown which is the D3D Manager. if it is valid we might use it if we + have an xvp in the path i.e. inputMediatype =! outputMediatype +--*/ + +STDMETHODIMP CPinQueue::RecreateTee( _In_ IMFMediaType *inMediatype, + _In_ IMFMediaType *outMediatype, + _In_opt_ IUnknown* punkManager ) +{ + HRESULT hr = S_OK; + MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal; + + DMFTCHECKNULL_GOTO(inMediatype, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(outMediatype, done, E_INVALIDARG); + + SAFE_DELETE(m_teer); + + CNullTee *nulltee = new (std::nothrow) CNullTee(); + DMFTCHECKNULL_GOTO( nulltee, done, E_OUTOFMEMORY); + + DMFTCHECKHR_GOTO( CompareMediaTypesForXVP(inMediatype, outMediatype, &operation), done); + + if ( (operation != DeviceMftTransformXVPCurrent) && (operation!= DeviceMftTransformXVPIllegal) ) + { + CXvptee* pXvptee = new (std::nothrow) CXvptee(nulltee); + DMFTCHECKNULL_GOTO(pXvptee, done, E_OUTOFMEMORY); + (void)pXvptee->SetD3DManager( punkManager ); + (void)pXvptee->SetMediaTypes( inMediatype, outMediatype ); + m_teer = dynamic_cast< Ctee* >( pXvptee ); + } + else + { + m_teer = nulltee; /*A simple passthrough*/ + } + +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + + if (FAILED(hr)) + { + if (m_teer){ + delete(m_teer); + m_teer = NULL; + } + + } + return hr; +} + +// +//State implementation +// +CPinOpenState::CPinOpenState(CBasePin *_pin) +:CPinState(DeviceStreamState_Run), m_pin(_pin) +{ + +} + + + +/*++ +Description: + This is the passthrough Tee in the literal sense i.e. It just dumps the sample + into the queue qupplied as an argument +--*/ +STDMETHODIMP CNullTee::PassThrough( _In_ IMFSample *pSample, _In_ CPinQueue *que ) +{ + HRESULT hr = S_OK; + + DMFTCHECKNULL_GOTO(pSample, done, S_OK); //No OP for a NULL Sample!!! + (VOID)que->InsertInternal(pSample); + + done: + return hr; +} + +/*++ +Description: + This function sets the Media types on the XVP or the decoder transform. Here is where we configure the XVP + or the Decoder or the Encoder tee if present. The first iteration only has the XVP added +--*/ +STDMETHODIMP CWrapTee::SetMediaTypes( _In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType ) +{ + HRESULT hr = S_OK; + IMFTransform *pTransform = nullptr; + + DMFTCHECKHR_GOTO(Configure( pInMediaType, pOutMediaType, &pTransform ),done); + m_videoProcessor = pTransform; + m_pInputMediaType = pInMediaType; + m_pOutputMediaType = pOutMediaType; + +done: + SAFE_RELEASE(pTransform); + return hr; +} + +/*++ +Description: +This is used when an XVP is present in the Pin. If the path is a passthrough i.e. +the media type on the input and the output pins are the same then we will not see +this path traversed. This function feeds the sample to the XVP or the decoding Tee +--*/ +STDMETHODIMP CWrapTee::PassThrough(_In_ IMFSample* pInSample, _In_ CPinQueue *pQue) +{ + HRESULT hr = S_OK; + IMFSample* pOutSample = nullptr; + + DMFTCHECKHR_GOTO(Do(pInSample, &pOutSample),done); + + if (m_objectWrapped) + { + hr = m_objectWrapped->PassThrough(pOutSample, pQue); + } + +done: + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + } + + return hr; +} + + +/*++ +CXvptee::Do +Description: +Called to do what an XVP is supposed to do i.e. scaling, resize etc. +This function is called when the samples are desposited from the input pin to the +output pin queue during a ProcessInput call on the device transform. Of course the +outpin should be in Open state for the sample to reach the XVP and consequetively the +Output Pin. + +If the DX manager is set on the Transform and we receieve a DX sample then we will +undertake the DX transform in the XVP else we will skip it and go the software way +--*/ +STDMETHODIMP CXvptee::Do(_In_ IMFSample *pSample, _Outptr_ IMFSample** pOutSample) +{ + // + //Since we are streaming in the software mode we will create a new sample + // + HRESULT hr = S_OK,pohr = S_OK; + MFT_OUTPUT_DATA_BUFFER outputSample; + MFT_OUTPUT_STREAM_INFO StreamInfo; + IMFSample* spXVPOutputSample = nullptr; + IMFMediaType* pOutMediaType = nullptr; + ComPtr <IMFMediaBuffer> spIMFMediaBuffer = nullptr; + GUID guidOutputSubType = GUID_NULL; + pOutMediaType = getOutMediaType(); + + DMFTCHECKNULL_GOTO(pOutSample, done, E_INVALIDARG); + + DMFTCHECKHR_GOTO(pOutMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done); + + BOOL isDx = false; + + if (SUCCEEDED(IsInputDxSample(pSample, &isDx)) && isDx) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! DX Sample sent to XVP %p", pSample); + } + + outputSample.dwStreamID = 0; + outputSample.pSample = NULL; + + if (!(isDx && m_spDeviceManagerUnk!=nullptr)) + { + // + //Create a new sample for software encoding + // + DMFTCHECKHR_GOTO(MFCreateSample(&spXVPOutputSample), done); + + DMFTCHECKHR_GOTO(pSample->CopyAllItems(spXVPOutputSample), done); + + outputSample.pSample = spXVPOutputSample; + + + DMFTCHECKHR_GOTO(Transform()->MFTGetOutputStreamInfo(0, &StreamInfo), done); + + if (!m_isOutPutImage) + { + DMFTCHECKHR_GOTO(MFGetAttributeSize(pOutMediaType, MF_MT_FRAME_SIZE, &m_uWidth, &m_uHeight), done); + hr = MFCreate2DMediaBuffer( + m_uWidth, + m_uHeight, + guidOutputSubType.Data1, + FALSE, // top-down buffer (DX compatible) + &spIMFMediaBuffer); + if (FAILED(hr)) + { + spIMFMediaBuffer = nullptr; + spXVPOutputSample->Release(); + + DMFTCHECKHR_GOTO(MFCreateAlignedMemoryBuffer( + StreamInfo.cbSize, + StreamInfo.cbAlignment, + &spIMFMediaBuffer), done); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured without DX, Created a 1D buffer"); + + } + else + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured with DX, Created a 2D buffer"); + } + DMFTCHECKHR_GOTO(spXVPOutputSample->AddBuffer(spIMFMediaBuffer.Get()), done); + } + } + + + // + //Start streaming the xvp transform.. + // + DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), done); // ulParam set to zero + DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), done); // ulParam set to zero + + + DMFTCHECKHR_GOTO(Transform()->MFTProcessInput(0, pSample, 0),done); + + DWORD dwStatus = 0; + + pohr = Transform()->MFTProcessOutput(0, 1, &outputSample, &dwStatus); + + if (FAILED(pohr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP ProcessOutput,failure %x sample =%p", pohr, &outputSample); + SAFERELEASE(spXVPOutputSample); + } + + DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), done); // Flush the stream + DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0), done); // Notify end of stream + DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0), done); // Notify end of streaming + + spXVPOutputSample = outputSample.pSample; + + if ( SUCCEEDED(pohr) ) + { + //Let us copy the timestamps + LONGLONG hnsSampleDuration = 0; + LONGLONG hnsSampleTime = 0; + + pSample->GetSampleDuration(&hnsSampleDuration); + pSample->GetSampleTime(&hnsSampleTime); + spXVPOutputSample->SetSampleDuration(hnsSampleDuration); + spXVPOutputSample->SetSampleTime(hnsSampleTime); + } + + *pOutSample = spXVPOutputSample; + // + //Release the Sample back to the pipeline + // + pSample->Release(); + +done: + hr = FAILED(pohr) ? pohr : hr; + return hr; +} + +/*++ +Description: + Set the D3D Manager on the XVP +--*/ +STDMETHODIMP_(VOID) CXvptee::SetD3DManager(IUnknown* pUnk) +{ + m_spDeviceManagerUnk = pUnk; +} +/*++ +Descrtiption: + Create the XVP Transform with the media types supplied. + This is invoked when an XVP is added to the Queue in the Output pins + and the input pins media type and the output pins media type don't match. + +--*/ +STDMETHODIMP CXvptee::Configure( + _In_opt_ IMFMediaType* inMediaType, + _In_opt_ IMFMediaType* outMediaType, + _Outptr_ IMFTransform **ppTransform + ) +{ + HRESULT hr = S_OK; + GUID inMajorType = GUID_NULL; + GUID outMajorType = GUID_NULL; + bool imageType = false; + bool optimized = false; + bool optimizedxvpneeded = false; + IMFMediaType *pXvpOutputMediaType = nullptr; + ComPtr<IMFAttributes> pXvpTransformAttributes = nullptr; + UINT32 width = 0, height = 0; + + DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG); + + m_isOutPutImage = false; + m_isoptimizedPlanarInputOutput = false; + + // + //Print out the Media type set on the XVP + // + { + CMediaTypePrinter inType(inMediaType); + CMediaTypePrinter outType(outMediaType); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Input MediaType %s", inType.ToString()); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Output MediaType %s", outType.ToString()); + } + + DMFTCHECKHR_GOTO( CoCreateInstance( + CLSID_VideoProcessorMFT, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(ppTransform)), done); + + + + DMFTCHECKHR_GOTO( inMediaType->GetMajorType( &inMajorType ),done ); + DMFTCHECKHR_GOTO( outMediaType->GetMajorType( &outMajorType ), done ); + // + //Configuring DX Manager in SW mode. We will look to make it DX complaint in the next phase + // + if ( !IsEqualGUID(MFMediaType_Video, outMajorType ) ) + { + imageType = true; + m_isOutPutImage = true; + IsOptimizedPlanarVideoInputImageOutputPair( + inMediaType, + outMediaType, + &optimized, + &optimizedxvpneeded ); + } + + // + //Disable frame rate conversion + // + DMFTCHECKHR_GOTO((*ppTransform)->GetAttributes(&pXvpTransformAttributes),done); + pXvpTransformAttributes->SetUINT32(MF_XVP_DISABLE_FRC, TRUE); + DMFTCHECKHR_GOTO( (*ppTransform)->MFTProcessMessage( MFT_MESSAGE_SET_D3D_MANAGER, NULL ), done ); + DMFTCHECKHR_GOTO((*ppTransform)->MFTSetInputType(0, inMediaType, 0), done); + + + DMFTCHECKHR_GOTO(MFCreateMediaType(&pXvpOutputMediaType), done); + DMFTCHECKHR_GOTO(outMediaType->CopyAllItems(pXvpOutputMediaType), done); + DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), done); //Video propcessor doesn't understand image types + + + if ( imageType ) + { + GUID guidSub; + + if ( !optimized ) + { + DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done ); + if ( IsEqualGUID( guidSub, MFVideoFormat_ARGB32 ) ) + { + DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32), done); + } + else + { + DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), done); + } + DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done); + + m_uWidth = width; + m_uHeight = height; + + DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, width * 4), done); //So we always get a top down buffer + + DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done); + } + else + { + //*** If we come here we know that the XVP is needed + //This case should be for non planar and xvp needed cases which we will always assume + LONG cStride = 0; + //For now we will just assume that we need the xvp in all cases + DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done ); + + DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, guidSub), done); + + DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done); + + DMFTCHECKHR_GOTO( MFGetStrideForBitmapInfoHeader( guidSub.Data1, width, &cStride ), done ); + + DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, cStride), done); //So we always get a top down buffer for Nv12/Yv12 + + DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255), done); //Always set nominal range to 0-255 to feed into a WIC encoder + + DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done); + } + } + else + { + DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, outMediaType, 0), done); + } + if ((m_spDeviceManagerUnk != nullptr)) + { + // + //Set the D3D Manager on the XVP if present + // + DMFTCHECKHR_GOTO((*ppTransform)->MFTProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, + reinterpret_cast<ULONG_PTR>(m_spDeviceManagerUnk.Get())), done); + } +done: + SAFE_RELEASE(pXvpOutputMediaType); + return hr; + +} + + +CXvptee::CXvptee( _In_ Ctee *tee) : +CWrapTee(tee), + m_isOutPutImage(false), + m_isoptimizedPlanarInputOutput(true), + m_spDeviceManagerUnk(nullptr), + m_uHeight(0), + m_uWidth(0) + +{ + +} + + +CXvptee::~CXvptee() +{ + m_spDeviceManagerUnk = nullptr; +} + +//To be implemented..Not needed for the sample!! +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +STDMETHODIMP CDecoderTee::Do(_In_ IMFSample* pSample, _Out_ IMFSample **pOutSample ) +{ + UNREFERENCED_PARAMETER(pSample); + UNREFERENCED_PARAMETER(pOutSample); + return S_OK; +} +STDMETHODIMP CDecoderTee::Configure( _In_opt_ IMFMediaType *inMediaType, _In_opt_ IMFMediaType *outMediaType, _Outptr_ IMFTransform** ppTransform) +{ + HRESULT hr = S_OK; + GUID guidcategory = GUID_NULL; + BOOL IsDecoder = true; + UINT32 unFlags = 0; + MFT_REGISTER_TYPE_INFO in; + MFT_REGISTER_TYPE_INFO out; + UINT32 cActivates = 0; + UINT32 unMFTFlags = 0; + ComPtr<IMFMediaType> pInputMediaType = nullptr; + ComPtr<IMFMediaType> pOutputMediaType = nullptr; + IMFActivate **ppActivates = nullptr; + DWORD dwInputStreams; + DWORD dwOutputStreams; + UNREFERENCED_PARAMETER(outMediaType); + UNREFERENCED_PARAMETER(inMediaType); + UNREFERENCED_PARAMETER(ppTransform); + + guidcategory = (IsDecoder)?MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_ENCODER; + + if (IsDecoder) + { + DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &in.guidMajorType), done); + DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_SUBTYPE, &in.guidSubtype), done); + } + else + { + DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &out.guidMajorType), done); + DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &out.guidSubtype), done); + } + + // + //Use all possible plugins + // + + unFlags = MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_SORTANDFILTER_WEB_ONLY; + DMFTCHECKHR_GOTO(MFTEnumEx(guidcategory, + unFlags, + IsDecoder ? &in : NULL, + IsDecoder ? NULL : &out, + &ppActivates, + &cActivates + ),done); + if (cActivates!=0) + { + DMFTCHECKHR_GOTO(MF_E_TOPO_CODEC_NOT_FOUND, done); + } + for (DWORD dwIndex = 0; dwIndex < cActivates; dwIndex++) + { + // + //Check if this MFT requires an unlocking.. skip if it does + // + unMFTFlags = MFGetAttributeUINT32(ppActivates[dwIndex], MF_TRANSFORM_FLAGS_Attribute, 0); + if (unMFTFlags & MFT_ENUM_FLAG_FIELDOFUSE) + { + // + //If you have the unlocking key set MFT_FIELDOFUSE_UNLOCK_Attribute on the activate + // + continue; + } + + hr = ppActivates[dwIndex]->ActivateObject(IID_PPV_ARGS(ppTransform)); + if (FAILED(hr)) + continue; //hope the next activate is activable + ppActivates[dwIndex]->DetachObject(); + + hr = (*ppTransform)->MFTGetStreamCount(&dwInputStreams, &dwOutputStreams); + + if (FAILED(hr) || dwInputStreams != 1 || dwOutputStreams > 127)//remove the hardcoding + { + // + //Exception.. we can't use a stream that doesn't give us an idea about it's streams + // + continue; + } + if (IsDecoder) + { + hr = ConfigureDecoder(*ppTransform); + } + else + { + hr = ConfigureEncoder(*ppTransform); + } + if (FAILED(hr)) + { + SAFE_RELEASE(*ppTransform); + } + } + +done: + return hr; +} + +/*++ + +--*/ + +STDMETHODIMP CDecoderTee::ConfigureEncoder( _In_ IMFTransform *pTransform ) +{ + HRESULT hr = S_OK; + // + //Set the input media type and the output media type and that should be pretty much it + // + ComPtr<IMFMediaType> pInputType = nullptr; + ComPtr<IMFMediaType> pOutputType = nullptr; + + pInputType = getInMediaType(); + pOutputType = getOutMediaType(); + + if (pInputType && pOutputType) + { + //We should be good by now + DMFTCHECKHR_GOTO( pTransform->MFTSetInputType( 0,pInputType.Get(), 0), done); + //If we have D3D enabled then try again with D3D disabled and see the result + // + DMFTCHECKHR_GOTO(pTransform->MFTSetOutputType(0,pOutputType.Get(), 0), done); + // + //If the above operation fails and we are allowing partial media types then + //we have to find the full media type and then check again + } + else + { + hr = E_FAIL; + } +done: + return hr; +} + +STDMETHODIMP CDecoderTee::ConfigureDecoder( _In_ IMFTransform *pTransform) +{ + UNREFERENCED_PARAMETER( pTransform ); + return S_OK; +} + +/*++ +Descrtiption: + Handles events sent by the pipeline + --*/ +STDMETHODIMP CDMFTEventHandler::KSEvent( + _In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned) +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(ulDataLength); + UNREFERENCED_PARAMETER(pBytesReturned); + + if (pEvent == nullptr) + { + // + // We can have an Event Reset here + // + if (pEventData == nullptr) + { + // + // Invalid input. KSEVENT and KSEVENTDATA cannot both be null + // + DMFTCHECKHR_GOTO(E_INVALIDARG, done); + } + // + // The way KSevents work are, KSEVENT and KSEVENTDATA both have to be non null for events to be Set + // on the driver. If the pipeline wishes to reset the event we pass the KSEVENT structure as NULL and + // the KSEVENTDATA to be nonnull. + // ********** EVENT RESET here since KSEVENT is null and KSEVENTDATA is not********** + // We will never get Event Reset for One shot events + // Search the list of regular events to find the KSEVENTDATA pointer and then free the entry + // + for ( vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it ) + { + PDMFTEventEntry pEntry = nullptr; + pEntry = *it; + DMFTCHECKNULL_GOTO(pEntry, done, E_UNEXPECTED); // We should never see a null data structure entry + if (pEntry->m_pEventData == pEventData) + { + it = m_RegularEventList.erase(it); + delete(pEntry); // Delete the entry! + goto done; + } + } + + DMFTCHECKHR_GOTO(E_NOT_SET, done); + } + else + { + // + // If we are here the pipeline wants to do the following things + // 1) Store a regular event + // 2) Store a oneshot event + // + HANDLE evtHandle = nullptr; + PKSEVENT pEvt = pEvent; + PKSEVENTDATA pEvtdata = reinterpret_cast<PKSEVENTDATA>(pEventData); + + if (ulEventLength < sizeof(KSEVENT)) + { + DMFTCHECKNULL_GOTO(pBytesReturned, done, E_INVALIDARG); + *pBytesReturned = sizeof(KSEVENT); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); + } + + if (!pEvtdata) + { + // + // Need the event data to be present to service the call properly! + // + DMFTCHECKHR_GOTO(E_INVALIDARG, done); + } + + if (pEvt->Flags & KSEVENT_TYPE_ENABLE) // Regular/ Manual Reset Event + { + vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); + for (; it != m_RegularEventList.end(); it++) + { + PDMFTEventEntry pEntry = *it; + DMFTCHECKNULL_GOTO(pEntry, done, E_FAIL); + if (pEntry->m_pEventData == pEventData) + { + break; + } + } + if (it != m_RegularEventList.end()) + { + // + // Duplicate entry found. + // + DMFTCHECKHR_GOTO(E_NOT_VALID_STATE, done); + } + } + else if (pEvt->Flags & KSEVENT_TYPE_ONESHOT) + { + ULONG ulEventCommand = pEvt->Id; + hr = ExceptionBoundary([&]() + { + map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventCommand); + if (it != m_OneShotEventMap.end()) + { + // + // Duplicate entry found. + // + hr = E_NOT_VALID_STATE; + } + }); + DMFTCHECKHR_GOTO(hr, done); + } + else + { + DMFTCHECKHR_GOTO(E_NOTIMPL, done); + } + + // + // Duplicate the handle + // + DMFTCHECKHR_GOTO(Dupe(pEvtdata->EventHandle.Event, &evtHandle),done); + ULONG ulEventCommand = pEvt->Id; + + if (pEvt->Flags & KSEVENT_TYPE_ENABLE) + { + // ************** REGULAR EVENT **************************** + // Regualar event. When this needs to be cleqared we will geta call with KSEVENT = null + // and KSEVENTDATA with the same address as this call(pEvtdata). Hence store it + // To set the event all we need is the EVENT id. + // + PDMFTEventEntry pEntry = new DMFTEventEntry(ulEventCommand, pEvtdata, evtHandle); + DMFTCHECKNULL_GOTO(pEntry, done, E_OUTOFMEMORY); + hr = ExceptionBoundary([&]() + { + (VOID)m_RegularEventList.push_back(pEntry); + }); + } + else if(pEvt->Flags & KSEVENT_TYPE_ONESHOT) + { + // *************** SINGLE SHOT EVENT ************************ + // Single Shot event store. Store the event Id and the Handle. + // + hr = ExceptionBoundary([&]() + { + (VOID)m_OneShotEventMap.insert(std::pair<ULONG, HANDLE>(ulEventCommand, evtHandle)); + }); + DMFTCHECKHR_GOTO(hr, done); + } + } + +done: + return hr; +} + +/*++ +Descrtiption: + Used to set the One shot events sent by the pipeline. + One shot events should be closed by the component after firing. The Pipeline + will not send a reset or a clear for one shot events +--*/ + +STDMETHODIMP CDMFTEventHandler::SetOneShot( ULONG ulEventId ) +{ + HRESULT hr = S_OK; + hr = ExceptionBoundary([&]() + { + map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventId); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! trying to Set OneShot %d ", ulEventId); + + if (it != m_OneShotEventMap.end()) + { + // Found the event + HANDLE hOneShot = it->second; + if (SetEvent(hOneShot)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d Succeeded", + ulEventId); + CloseHandle(hOneShot); + m_OneShotEventMap.erase(it); + } + else + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x", + ulEventId, + HRESULT_FROM_WIN32(GetLastError())); + } + } + else + { + hr = E_NOT_SET; + } + }); + DMFTCHECKHR_GOTO(hr, done); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x", + ulEventId, + HRESULT_FROM_WIN32(GetLastError())); + return hr; +} + +/*++ +Descrtiption: + Used to set the Regular events sent by the pipeline. + Regular events unlike the one shot events must be persisted + until the pipeline explicitly needs the event to be unset. +--*/ + +STDMETHODIMP CDMFTEventHandler::SetRegularEvent(ULONG ulEventId) +{ + BOOL bEvtFound = FALSE; + HRESULT hr = ExceptionBoundary([&]() + { + + for (vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it) + { + PDMFTEventEntry pEntry = *it; + if (ulEventId == pEntry->m_ulEventId) + { + // Found the event + bEvtFound = TRUE; + if (!::SetEvent(pEntry->m_hHandle)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d Failed 0x%x", + ulEventId, hr); + } + else + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d s", + ulEventId); + } + } + } + }); + if (!bEvtFound) + { + DMFTCHECKHR_GOTO(E_NOT_SET, done); + } +done: + return hr; +} + +/*++ +Descrtiption: + Duplicates the handle passed. +--*/ + +STDMETHODIMP CDMFTEventHandler::Dupe(_In_ HANDLE hEventHandle, _Outptr_ LPHANDLE lpTargetHandle) +{ + HRESULT hr = S_OK; + DMFTCHECKNULL_GOTO(hEventHandle, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(lpTargetHandle, done, E_INVALIDARG); + // + // Duplicate handle and store it for when it needs to be fired + // + if (!DuplicateHandle(GetCurrentProcess(), hEventHandle, + GetCurrentProcess(), lpTargetHandle, + 0, + false, + DUPLICATE_SAME_ACCESS + )) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Duplicating Event Handle failed %x", + hr); + DMFTCHECKHR_GOTO(hr, done); + } +done: + return hr; +} + +/*++ + +Descrtiption: + Cleans the event lists, both the Single shot and the Regular ones + +--*/ +STDMETHODIMP CDMFTEventHandler::Clear() +{ + HRESULT hr = S_OK; + hr = ExceptionBoundary([&]() + { + map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.begin(); + for (; it != m_OneShotEventMap.end(); ++it) + { + // + // Delete the one shot entries. We should not see this path usually + // as the pipeline will send a one shot event and set it soon. We + // should remore the entry then. + // + CloseHandle(it->second); + it = m_OneShotEventMap.erase(it); + if (it == m_OneShotEventMap.end()) + { + // We've reached the end break + break; + } + } + }); + DMFTCHECKHR_GOTO(hr, done); + hr = ExceptionBoundary([=]() + { + vector<PDMFTEventEntry>::iterator it2 = m_RegularEventList.begin(); + for (; it2 != m_RegularEventList.end(); ++it2) + { + // + // Delete the entries. This will be traversed + // + PDMFTEventEntry pEntry = *it2; + it2 = m_RegularEventList.erase(it2); + SAFE_DELETE(pEntry); + if (it2 == m_RegularEventList.end()) + { + break; + } + } + }); + DMFTCHECKHR_GOTO(hr, done); +done: + return hr; +} diff --git a/AVStream/sampledevicemft/multipinmfthelpers.h b/AVStream/sampledevicemft/multipinmfthelpers.h new file mode 100644 index 00000000..25d87eb8 --- /dev/null +++ b/AVStream/sampledevicemft/multipinmfthelpers.h @@ -0,0 +1,291 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// +#pragma once +#include "stdafx.h" +#include "common.h" + + + +// +//Queue class!!! +// +class Ctee; +//typedef CMFAttributesTrace CMediaTypeTrace; /* Only used for debug. take this out*/ + + +class CPinQueue{ +public: + CPinQueue(_In_ DWORD _inPinId); + ~CPinQueue(); + + STDMETHODIMP_(BOOL) SetState ( _In_ BOOL state ); + STDMETHODIMP_(VOID) InsertInternal ( _In_ IMFSample *pSample = nullptr ); + STDMETHODIMP_(BOOL) Insert ( _In_ IMFSample *pSample ); + STDMETHODIMP_(BOOL) Remove (_Outptr_result_maybenull_ IMFSample **pSample); + STDMETHODIMP RecreateTee ( _In_ IMFMediaType *inMediatype, _In_ IMFMediaType *outMediatype, _In_opt_ IUnknown* punkManager ); + STDMETHODIMP_(VOID) Clear(); + + // + //Inline functions + // + __inline BOOL Empty() + { + return (!m_sampleList.size()); + } + + __inline DWORD pinStreamId() + { + return m_dwInPinId; + } + +private: + DWORD m_dwInPinId; /*This is the input pin */ + IMFSampleList m_sampleList; /*List storing the samples */ + ULONG m_sampleCount; /*Numebr of sampels */ + Ctee* m_teer; /*Tee that acts as a passthrough or an XVP */ + BOOL m_discotinuity; /*Set after the queue is emptied or flushed */ + +}; + +class CPinState{ +public: + virtual STDMETHODIMP Open() = 0; + CPinState( _In_ DeviceStreamState _state = DeviceStreamState_Disabled) :m_State( _state ) + { + + } + STDMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState ); /*True for Active and False for Stop*/ + STDMETHODIMP_(DeviceStreamState) GetState(); + + __inline STDMETHODIMP_(DeviceStreamState) State() + { + return m_State; + } + virtual ~CPinState() = 0 + { + } +protected: + DeviceStreamState m_State; +}; + +class CPinOpenState :public CPinState{ +public: + CPinOpenState( _In_ CBasePin *p = NULL ); + // + //Inline + // + __inline STDMETHODIMP Open() + { + return S_OK; + } + +private: + CBasePin *m_pin; +}; +class CPinClosedState : public CPinState{ +public: + CPinClosedState(DeviceStreamState _state = DeviceStreamState_Stop) + :CPinState(_state) + { + + } + // + //Inline + // + __inline STDMETHODIMP Open() + { + return MF_INVALID_STATE_ERR; + } +}; + + + +// +// Define these in different components +// The below classes are used to add the +// XVP and the Decoder components +// +class Ctee{ +public: + virtual STDMETHODIMP PassThrough( _In_ IMFSample *, _In_ CPinQueue * ) = 0; +}; + + +class CNullTee:public Ctee{ +public: + STDMETHODIMP PassThrough( _In_ IMFSample*, _In_ CPinQueue * ); +}; + + +class CWrapTee : public Ctee{ +public: + CWrapTee(_In_ Ctee *tee=nullptr) +: m_objectWrapped(tee) + , m_pInputMediaType(nullptr) + , m_pOutputMediaType(nullptr) + { + + } + virtual ~CWrapTee()=0 + { + m_videoProcessor = nullptr; + if (m_objectWrapped) + { + delete(m_objectWrapped); + } + } + + STDMETHODIMP PassThrough ( _In_ IMFSample*, _In_ CPinQueue * ); + virtual STDMETHODIMP Configure ( _In_ IMFMediaType *, _In_ IMFMediaType *, _Inout_ IMFTransform** ) = 0; + virtual STDMETHODIMP Do ( _In_ IMFSample* pSample, _Out_ IMFSample ** ) = 0; + STDMETHODIMP SetMediaTypes ( _In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType ); + + // + //Inline functions + // +protected: + __inline IMFTransform* Transform() + { + return m_videoProcessor.Get(); + } + __inline IMFMediaType* getInMediaType() + { + IMFMediaType* pmediaType = nullptr; + m_pInputMediaType.CopyTo(&pmediaType); + return pmediaType; + } + __inline IMFMediaType* getOutMediaType() + { + IMFMediaType* pmediaType = nullptr; + m_pOutputMediaType.CopyTo(&pmediaType); + return pmediaType; + } + +private: + ComPtr< IMFTransform > m_videoProcessor; + ComPtr< IMFMediaType > m_pInputMediaType; + ComPtr< IMFMediaType > m_pOutputMediaType; + Ctee *m_objectWrapped; +}; + + +class CXvptee :public CWrapTee{ +public: + CXvptee( _In_ Ctee * ); + ~CXvptee(); + STDMETHODIMP Do ( _In_ IMFSample* pSample, _Outptr_ IMFSample ** ); + STDMETHODIMP Configure ( _In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform** ); + STDMETHODIMP_(VOID) SetD3DManager( IUnknown* punk ); + +private: + BOOL m_isoptimizedPlanarInputOutput; + BOOL m_isOutPutImage; + UINT32 m_uWidth; + UINT32 m_uHeight; + ComPtr<IUnknown> m_spDeviceManagerUnk; +}; + +class CDecoderTee : public CWrapTee{ +public: + CDecoderTee(Ctee* *); + ~CDecoderTee(); + + STDMETHODIMP Do( _In_ IMFSample* pSample, _Out_ IMFSample ** ); + STDMETHODIMP Configure( _In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform** ); + STDMETHODIMP ConfigureEncoder( _In_ IMFTransform *pTransform ); + STDMETHODIMP ConfigureDecoder( _In_ IMFTransform *pTransform ); +private: + ComPtr<IUnknown> m_spDeviceManagerUnk; +}; + + +/* +################## EVENT HANDLING ############################################# +Events are usually divided into two categories by the Capture Pipeline +1) Regular Event / Manual Reset Event +2) One Shot Event + +Regular events are set and cleared by the pipeline +One shot Events will only be set by the pipeline and it should be cleared +by the Component managing the Event Store i.e. KS or DMFT. For Redstone +The pipeline should not send any Non One shot events.This sample however +does show the handling of Regular/ Manual Reset events + +This clearing of One shot events is done when the event is fired.. +E.g before sending the warm start command The pipeline will send a one shot event +KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART and when the operation completes the +event should be fired. +The Device MFT should usually keep a watch for one shot events sent by the Pipeline +for Async Extended controls..The list of Asynchronous controls are as follows.. + +KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE +KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE +KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE +KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID +KSPROPERTY_CAMERACONTROL_EXTENDED_ISO +KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED +KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION +KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE +KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE +KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE +KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL +KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART +KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL +KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE +The complete list can be found from the Camera DDI spec +############################################################################### +*/ + +typedef struct _DMFTEventEntry{ + ULONG m_ulEventId; // KSEVENT->Id + PVOID m_pEventData; // Lookup for events in the data structure + HANDLE m_hHandle; // The duplicate handle stored from the event + // + // Constructor. We simply cache the handles, the property id and the KSEVENTDATA buffer sent from the user mode + // + _DMFTEventEntry( _In_ ULONG ulEventId, _In_ PVOID pEventData, _In_ HANDLE pHandle):m_pEventData(pEventData) + , m_ulEventId(ulEventId) + , m_hHandle(pHandle) + { + } + ~_DMFTEventEntry() + { + if ( m_hHandle != nullptr ) + { + CloseHandle(m_hHandle); + m_hHandle = nullptr; + } + } + +}DMFTEventEntry, *PDMFTEventEntry; + +// +// Handler for one shot events and Normal events +// +class CDMFTEventHandler{ +public: + // + // Handle the events here + // + STDMETHOD(KSEvent)(_In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned); + STDMETHOD(SetOneShot)(ULONG); + STDMETHOD(SetRegularEvent)(ULONG); + STDMETHOD(Clear)(); +protected: + STDMETHOD(Dupe)(_In_ HANDLE hEventHandle, _Outptr_ LPHANDLE lpTargetHandle); +private: + map< ULONG, HANDLE > m_OneShotEventMap; + vector< PDMFTEventEntry > m_RegularEventList; +}; + + + diff --git a/AVStream/sampledevicemft/multipinmftutils.cpp b/AVStream/sampledevicemft/multipinmftutils.cpp new file mode 100644 index 00000000..6f5735b5 --- /dev/null +++ b/AVStream/sampledevicemft/multipinmftutils.cpp @@ -0,0 +1,877 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" +#include "common.h" +#include "multipinmft.h" +#include "basepin.h" + +#pragma comment(lib, "d2d1") +#ifdef MF_WPP +#include "multipinmftutils.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif + +// Critical sections + +CCritSec::CCritSec() +{ + InitializeCriticalSection(&m_criticalSection); +} + +CCritSec::~CCritSec() +{ + DeleteCriticalSection(&m_criticalSection); +} + +_Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection) +void CCritSec::Lock() +{ + EnterCriticalSection(&m_criticalSection); +} + +_Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection) +void CCritSec::Unlock() +{ + LeaveCriticalSection(&m_criticalSection); +} + + +_Acquires_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::CAutoLock(CCritSec& crit) +{ + m_pCriticalSection = &crit; + m_pCriticalSection->Lock(); +} +_Acquires_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::CAutoLock(CCritSec* crit) +{ + m_pCriticalSection = crit; + m_pCriticalSection->Lock(); +} +_Releases_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::~CAutoLock() +{ + m_pCriticalSection->Unlock(); +} + +// +//Some utility functions.. +// + +/*++ + Description: + Used to check if the input and the output Image types are optinmized or not +--*/ + +STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair( + _In_ IMFMediaType *inMediaType, + _In_ IMFMediaType *outMediaType, + _Out_ bool *optimized, + _Out_ bool *optimizedxvpneeded ) +{ + HRESULT hr = S_OK; + GUID guidInputSubType = GUID_NULL; + GUID guidOutputSubType = GUID_NULL; + UINT32 uWidthIn = 0, uHeightIn = 0, uWidthOut = 0, uHeightOut = 0; + + + DMFTCHECKHR_GOTO(inMediaType->GetGUID(MF_MT_SUBTYPE, &guidInputSubType), done); + + DMFTCHECKHR_GOTO(outMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done); + + *optimized = false; //Assume we aren't optimized . Optimized = (ip = YU12|NV12 and op = JPEG) + *optimizedxvpneeded = true; //Assume we need xvps + + if (IsEqualGUID(guidInputSubType, MFVideoFormat_YV12) || IsEqualGUID(guidInputSubType, MFVideoFormat_NV12)) + { + if (IsEqualGUID(guidOutputSubType, GUID_ContainerFormatJpeg)) + { + *optimized = true; + } + } + + if (!*optimized) + { + goto done; + } + + DMFTCHECKHR_GOTO(MFGetAttributeSize(inMediaType, MF_MT_FRAME_SIZE, &uWidthIn, &uHeightIn), done); + DMFTCHECKHR_GOTO(MFGetAttributeSize(outMediaType, MF_MT_FRAME_SIZE, &uWidthOut, &uHeightOut), done); + + if ((uWidthIn == uWidthOut) && (uHeightIn == uHeightOut)) + { + *optimizedxvpneeded = false; + } + if (!*optimizedxvpneeded) + { + UINT32 nominalRange; + hr = inMediaType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange); + + if (FAILED(hr) || nominalRange != MFNominalRange_0_255) + { + //XVP needed since nominal range is not 0-255 for YV12 or NV12 fed into WIC + *optimizedxvpneeded = true; + } + hr = S_OK; + } + +done: + return hr; +} + + +/* +Description: + + This is used whenever there is a media type change on an output pin and the + Output queue is being reconfigured. + The possible return values for the function are as follows + + DeviceMftTransformXVPIllegal -> If either of the mediatypes or both are NULL + DeviceMftTransformXVPDisruptiveIn -> If the mediatype at the output pin is greater than the input pin. This will result in change of the media type on the input + DeviceMftTransformXVPDisruptiveOut -> This is a reconfiguration or addition of the XVP in the Output pin queue + DeviceMftTransformXVPCurrent -> No XVP needed at all + Note: This iteration doesn't support decoder. The next one will and this function will accordingly change +*/ +STDMETHODIMP CompareMediaTypesForXVP( + _In_opt_ IMFMediaType *inMediaType, + _In_ IMFMediaType *newMediaType, + _Inout_ MF_TRANSFORM_XVP_OPERATION *operation + ) +{ + UINT32 unWidthin, unHeightin, unWidthNew, unHeightNew = 0; + HRESULT hr = S_OK; + GUID guidTypeA = GUID_NULL; + GUID guidTypeB = GUID_NULL; + + *operation = DeviceMftTransformXVPIllegal; + if ((!inMediaType) || (!newMediaType)) + { + goto done; + } + + DMFTCHECKHR_GOTO( MFGetAttributeSize( inMediaType, MF_MT_FRAME_SIZE, &unWidthin, &unHeightin ), done ); + DMFTCHECKHR_GOTO( MFGetAttributeSize( newMediaType, MF_MT_FRAME_SIZE, &unWidthNew, &unHeightNew ), done ); + + + if ( SUCCEEDED( inMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeA ) ) && + SUCCEEDED( newMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeB ) ) && + IsEqualGUID( guidTypeA, guidTypeB ) ) + { + if ( SUCCEEDED( inMediaType->GetGUID ( MF_MT_SUBTYPE, &guidTypeA ) ) && + SUCCEEDED( newMediaType->GetGUID( MF_MT_SUBTYPE, &guidTypeB ) ) && + IsEqualGUID( guidTypeA, guidTypeB ) ) + { + //Comparing the MF_MT_AM_FORMAT_TYPE for the directshow format guid +#if 0 + if (SUCCEEDED(inMediaType->GetGUID(MF_MT_AM_FORMAT_TYPE, &guidTypeA)) && + SUCCEEDED(newMediaType->GetGUID(MF_MT_AM_FORMAT_TYPE, &guidTypeB)) && + IsEqualGUID(guidTypeA, guidTypeB)) +#endif + { + + if (!(( unWidthin == unWidthNew ) && + ( unHeightin == unHeightNew ) ) ) + { + if ( ( unWidthNew > unWidthin ) || ( unHeightNew > unHeightin ) ) + { + *operation = DeviceMftTransformXVPDisruptiveIn; //Media type needs to change at input + } + else + { + *operation = DeviceMftTransformXVPDisruptiveOut; //Media type needs to change at output + } + goto done; + } + + if ( MFGetAttributeUINT32( inMediaType, MF_MT_SAMPLE_SIZE, 0 ) != + MFGetAttributeUINT32( newMediaType, MF_MT_SAMPLE_SIZE, 0 ) ) + { + hr = S_FALSE; //Sample sizes differ. + goto done; + } + else + { + //Same media type.. No XVP needed or the current XVP is fine! + *operation = DeviceMftTransformXVPCurrent; + } + } + } + else + { + //This is a disruptive operation. Actually a decoder operation! + *operation = DeviceMftTransformXVPDisruptiveIn; + } + } + done: + return hr; +} + +/*++ +Description: + A Simple function to randomnize the media types supplied in an array +--*/ +STDMETHODIMP RandomnizeMediaTypes(_In_ IMFMediaTypeArray &pMediaTypeArray) +{ + HRESULT hr = S_OK; + IMFMediaType *pTempMediaType = nullptr; + UNREFERENCED_PARAMETER(pTempMediaType); + if (pMediaTypeArray.empty()) + { + goto done; + } + + srand(static_cast<unsigned long>(GetTickCount64())); + + for (DWORD dwIndex = (DWORD)pMediaTypeArray.size() - 1; dwIndex > 0; dwIndex--) + { + DWORD fromIndex = rand() % ( dwIndex + 1 ); + pTempMediaType = pMediaTypeArray[dwIndex]; + pMediaTypeArray [ dwIndex ] = pMediaTypeArray[fromIndex] ; + pMediaTypeArray [ fromIndex ] = pTempMediaType; + } + // + //Just reverse the array + // + for (DWORD dwIndex = (DWORD)pMediaTypeArray.size() - 1, fromIndex = 0; dwIndex > 0; dwIndex--, fromIndex++) + { + + pTempMediaType = pMediaTypeArray[dwIndex]; + pMediaTypeArray [ dwIndex ] = pMediaTypeArray[fromIndex]; + pMediaTypeArray [ fromIndex ] = pTempMediaType; + } + done: + return hr; + +} + +/*++ +Description: Used to test if the sample passed is a DX sample or not? +--*/ +STDMETHODIMP IsInputDxSample( + _In_ IMFSample* pSample, + _Inout_ BOOL *isDxSample + ) +{ + HRESULT hr = S_OK; + ComPtr<IMFMediaBuffer> spBuffer = nullptr; + DMFTCHECKNULL_GOTO( pSample, done, E_INVALIDARG ); + + *isDxSample = false; + if ( SUCCEEDED( pSample->GetBufferByIndex( 0, &spBuffer ) ) ) + { + ComPtr<IMFDXGIBuffer> spDXGIBuffer; + ComPtr<ID3D11Texture2D> spResourceTexture; + if ( SUCCEEDED( spBuffer.As(&spDXGIBuffer ) ) && + SUCCEEDED( spDXGIBuffer-> GetResource( IID_PPV_ARGS( &spResourceTexture ) ) ) ) + { + *isDxSample = true; + } + } +done: + return hr; +} + + +/*++ + Description: + Helper function to return back if the Pin is in stopped stateo or not +--*/ +STDMETHODIMP_(BOOL) IsPinStateInActive( _In_ DeviceStreamState state) +{ + if ((state == DeviceStreamState_Disabled) || + (state == DeviceStreamState_Stop)) + { + return TRUE; + } + return FALSE; +} + +/* +Description: + A Helper function to return if the Mediatype is a compressed video type or not! +*/ +STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType(_In_ GUID guidSubType) +{ + if (guidSubType == MFVideoFormat_ARGB32 || + guidSubType == MFVideoFormat_RGB24 || + guidSubType == MFVideoFormat_RGB555 || + guidSubType == MFVideoFormat_RGB565 || + guidSubType == MFVideoFormat_RGB32 || + guidSubType == MFVideoFormat_RGB8 || + guidSubType == MFVideoFormat_AI44 || + guidSubType == MFVideoFormat_AYUV || + guidSubType == MFVideoFormat_YUY2 || + guidSubType == MFVideoFormat_YVYU || + guidSubType == MFVideoFormat_YVU9 || + guidSubType == MFVideoFormat_UYVY || + guidSubType == MFVideoFormat_NV11 || + guidSubType == MFVideoFormat_NV12 || + guidSubType == MFVideoFormat_YV12 || + guidSubType == MFVideoFormat_I420 || + guidSubType == MFVideoFormat_IYUV || + guidSubType == MFVideoFormat_Y210 || + guidSubType == MFVideoFormat_Y216 || + guidSubType == MFVideoFormat_Y410 || + guidSubType == MFVideoFormat_Y416 || + guidSubType == MFVideoFormat_Y41P || + guidSubType == MFVideoFormat_Y41T || + guidSubType == MFVideoFormat_Y42T || + guidSubType == MFVideoFormat_P210 || + guidSubType == MFVideoFormat_P216 || + guidSubType == MFVideoFormat_P010 || + guidSubType == MFVideoFormat_P016 || + guidSubType == MFVideoFormat_v210 || + guidSubType == MFVideoFormat_v216 || + guidSubType == MFVideoFormat_v410 || + guidSubType == MFVideoFormat_L8 || + guidSubType == MFVideoFormat_L16 || + guidSubType == MFVideoFormat_D16) + { + return( TRUE ); + } + + return( FALSE ); +} + +/*++ +Description: + Function used to lock the MFT. +--*/ + +STDMETHODIMP UnLockAsynMFT(IMFTransform* pTransform) +{ + HRESULT hr = S_OK; + IMFAttributes *pAttributes; + UINT32 unValue; + + DMFTCHECKNULL_GOTO(pTransform,done, E_INVALIDARG); + DMFTCHECKHR_GOTO(pTransform->GetAttributes(&pAttributes),done); + DMFTCHECKHR_GOTO(pAttributes->GetUINT32(MF_TRANSFORM_ASYNC, &unValue), done); + + if (unValue) + { + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_TRANSFORM_ASYNC, true), done); + } + +done: + return hr; +} + + +#ifndef IF_EQUAL_RETURN +#define IF_EQUAL_RETURN(param, val) if(val == param) return #val +#endif + +#define checkAdjustBufferCap(a,len){\ + char* tStore = NULL; \ +if (a && strlen(a) > ((len * 7) / 10)){\ + tStore = a; \ + len *= 2; \ + a = new char[len]; \ +if (!a){\ +goto done;}\ + a[0] = 0; \ + strcat_s(a, len, tStore); \ + delete(tStore); }\ +} + + +/*++ +Description: + returns an ascii buffer for the GUID passed. The Caller should release the memory allocated +--*/ +LPSTR DumpGUIDA(_In_ REFGUID guid) +{ + LPOLESTR lpszGuidString = NULL; + char *ansiguidStr = NULL; + if (SUCCEEDED(StringFromCLSID(guid, &lpszGuidString))) + { + int mbGuidLen = 0; + mbGuidLen = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, NULL, 0, NULL, NULL); + if (mbGuidLen > 0) + { + mf_assert(mbGuidLen == (int)wcslen(lpszGuidString)); + ansiguidStr = new char[mbGuidLen]; + WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, ansiguidStr, mbGuidLen, NULL, NULL); + CoTaskMemFree(lpszGuidString); + ansiguidStr[mbGuidLen - 1] = 0; + } + } + return ansiguidStr; +} + +// +//Borrrowed from MDSN sample +// +LPCSTR GetGUIDNameConst(const GUID& guid) +{ + IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE); + IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT); + IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES); + IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED); + IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE); + IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX); + IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN); + IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO); + IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING); + IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE); + IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES); + IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES); + IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE); + IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED); + IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE); + IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE); + IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING); + IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE); + IF_EQUAL_RETURN(guid, MF_MT_PALETTE); + IF_EQUAL_RETURN(guid, MF_MT_USER_DATA); + IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1); + IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK); + IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK); + IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER); + IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT); + IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT); + IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION); + IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY); + IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC); + IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG); + + // Media types + + IF_EQUAL_RETURN(guid, MFMediaType_Audio); + IF_EQUAL_RETURN(guid, MFMediaType_Video); + IF_EQUAL_RETURN(guid, MFMediaType_Protected); + IF_EQUAL_RETURN(guid, MFMediaType_SAMI); + IF_EQUAL_RETURN(guid, MFMediaType_Script); + IF_EQUAL_RETURN(guid, MFMediaType_Image); + IF_EQUAL_RETURN(guid, MFMediaType_HTML); + IF_EQUAL_RETURN(guid, MFMediaType_Binary); + IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer); + + IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44') + IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV') + IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25') + IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl') + IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264') + IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420') + IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV') + IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2') + IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG); + IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43') + IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S') + IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V') + IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1') + IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1') + IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2') + IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11') + IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12') + IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010') + IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016') + IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210') + IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216') + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8); + IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY') + IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210') + IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3') + IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P); + IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T); + IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2') + IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12') + IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU); + + IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM + IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT + IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS + IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF + IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2 + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3 + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS + IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF + IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9 + IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3 + IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG + IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC + IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC + + return NULL; +} + + +LPSTR DumpAttribute( _In_ const MF_ATTRIBUTE_TYPE& type, + _In_ REFPROPVARIANT var) +{ + CHAR *tempStr = NULL; + tempStr = new CHAR[256]; + switch (type) + { + case MF_ATTRIBUTE_UINT32: + if (var.vt == VT_UI4) + { + sprintf_s(tempStr, 256, "%u", var.ulVal); + } + break; + case MF_ATTRIBUTE_UINT64: + if (var.vt == VT_UI8) + { + sprintf_s(tempStr, 256, "%I64d (high: %d low: %d)", var.uhVal.QuadPart, var.uhVal.HighPart, var.uhVal.LowPart); + } + break; + case MF_ATTRIBUTE_DOUBLE: + if (var.vt == VT_R8) + { + sprintf_s(tempStr, 256, "%.4f", var.dblVal); + } + break; + case MF_ATTRIBUTE_GUID: + if (var.vt == VT_CLSID) + { + return DumpGUIDA(*var.puuid); + } + break; + case MF_ATTRIBUTE_STRING: + if (var.vt == VT_LPWSTR) + { + sprintf_s(tempStr, 256, "%S", var.pwszVal); + } + break; + case MF_ATTRIBUTE_IUNKNOWN: + break; + default: + printf("(Unknown Attribute Type = %d) ", type); + break; + } + return tempStr; +} + +CMediaTypePrinter::CMediaTypePrinter( + _In_ IMFMediaType *_pMediaType ) + : pMediaType(_pMediaType), + m_pBuffer(NULL) +{ +} + +CMediaTypePrinter::~CMediaTypePrinter() +{ + if (m_pBuffer) + { + delete(m_pBuffer); + } +} + +/*++ +Description: +Rudimentary function to print the complete Media type +--*/ +PCHAR CMediaTypePrinter::ToCompleteString( ) +{ + HRESULT hr = S_OK; + UINT32 attrCount = 0; + GUID attrGuid = { 0 }; + char *tempStore = nullptr; + PROPVARIANT var; + LPSTR pTempBaseStr; + MF_ATTRIBUTE_TYPE pType; + + if ( pMediaType && !m_pBuffer ) + { + DMFTCHECKHR_GOTO(pMediaType->GetCount(&attrCount), done); + buffLen = MEDIAPRINTER_STARTLEN; + m_pBuffer = new char[buffLen]; + m_pBuffer[0] = 0; + for ( UINT32 ulIndex = 0; ulIndex < attrCount; ulIndex++ ) + { + PropVariantInit( &var ); + checkAdjustBufferCap( m_pBuffer, buffLen ); + DMFTCHECKHR_GOTO( pMediaType->GetItemByIndex( ulIndex, &attrGuid, &var ), done ); + DMFTCHECKHR_GOTO( pMediaType->GetItemType( attrGuid, &pType ), done ); + if ( ulIndex > 0 ) + strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : "); + strcat_s( m_pBuffer, buffLen, GetGUIDNameConst( attrGuid ) ); + strcat_s( m_pBuffer, buffLen, "=" ); + pTempBaseStr = DumpAttribute( pType, var ); + strcat_s( m_pBuffer, buffLen, pTempBaseStr ); + delete( pTempBaseStr ); + PropVariantClear( &var ); + } + done: + if ( tempStore ) + { + delete( tempStore ); + } + } + return m_pBuffer; +} + +/*++ +Description: +Rudimentary function to print the Media type +--*/ + +PCHAR CMediaTypePrinter::ToString() +{ + // + //Following are the important ones of Mediatype attributes + // + + HRESULT hr = S_OK; + PROPVARIANT var; + LPSTR pTempBaseStr; + MF_ATTRIBUTE_TYPE pType; + GUID attrGuid; + GUID impGuids[] = { + MF_MT_SUBTYPE, + MF_MT_FRAME_SIZE, + MF_MT_SAMPLE_SIZE, + MF_MT_FRAME_RATE, + MF_MT_DEFAULT_STRIDE, + MF_XVP_DISABLE_FRC + }; + + if (pMediaType && !m_pBuffer) + { + buffLen = MEDIAPRINTER_STARTLEN; + m_pBuffer = new char[buffLen]; + m_pBuffer[0] = 0; + for (UINT32 ulIndex = 0; ulIndex < ARRAYSIZE(impGuids); ulIndex++) + { + PropVariantInit(&var); + checkAdjustBufferCap(m_pBuffer, buffLen); + attrGuid = impGuids[ulIndex]; + DMFTCHECKHR_GOTO(pMediaType->GetItemType(attrGuid, &pType), done); + DMFTCHECKHR_GOTO(pMediaType->GetItem(attrGuid, &var), done); + if (ulIndex > 0) + strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : "); + strcat_s(m_pBuffer, buffLen, GetGUIDNameConst(attrGuid)); + strcat_s(m_pBuffer, buffLen, "="); + pTempBaseStr = DumpAttribute(pType, var); + strcat_s(m_pBuffer, buffLen, pTempBaseStr); + delete(pTempBaseStr); + PropVariantClear(&var); + } + } +done: + return m_pBuffer; +} +/*++ +Description: + Debug message printer to print the message passed through WPP +--*/ +void printMessageEvent(MFT_MESSAGE_TYPE msg) +{ + switch (msg) + { + case MFT_MESSAGE_COMMAND_FLUSH: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_FLUSH"); + break; + case MFT_MESSAGE_COMMAND_DRAIN: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_DRAIN"); + break; + case MFT_MESSAGE_COMMAND_MARKER: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_MARKER"); + break; + case MFT_MESSAGE_COMMAND_TICK: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_TICK"); + break; + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_END_OF_STREAM"); + break; + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_BEGIN_STREAMING"); + break; + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_START_OF_STREAM"); + break; + case MFT_MESSAGE_DROP_SAMPLES: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_DROP_SAMPLES"); + break; + case MFT_MESSAGE_SET_D3D_MANAGER: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_SET_D3D_MANAGER"); + break; + + } +} + +/*++ +Below functions not used in the current iteration.. +--*/ +HRESULT CreateCodec( + _In_opt_ IMFMediaType* inMediaType, + _In_opt_ IMFMediaType *outMediaType, + _In_ BOOL operation /*True = Encode, False = Decode*/, + _Out_ IMFTransform **pTransform) +{ + UNREFERENCED_PARAMETER(inMediaType); + UNREFERENCED_PARAMETER(outMediaType); + UNREFERENCED_PARAMETER(operation); + UNREFERENCED_PARAMETER(pTransform); + HRESULT hr = S_OK; + *pTransform = nullptr; + return hr; +} + + +HRESULT CheckDX9RotationSupport(_In_ ID3D11VideoDevice* pVideoDevice) +{ + HRESULT hr = S_OK; + // + // check if the DX9 device is ok + // New drivers should have an DXVA-HD rotation cap set + // + D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc = {}; + D3D11_VIDEO_PROCESSOR_CAPS caps; + ComPtr<ID3D11VideoProcessorEnumerator> spVideoProcEnum = nullptr; + + DMFTCHECKNULL_GOTO(pVideoDevice, done, E_NOTIMPL); + desc.InputWidth = 640; + desc.InputHeight = 480; + desc.OutputWidth = 640; + desc.OutputHeight = 480; + + DMFTCHECKHR_GOTO(pVideoDevice->CreateVideoProcessorEnumerator(&desc, &spVideoProcEnum), done); + DMFTCHECKHR_GOTO(spVideoProcEnum->GetVideoProcessorCaps(&caps), done); + + if (!(caps.FeatureCaps & D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION)) + { + hr = E_NOTIMPL; + } +done: + return hr; +} + + + +HRESULT IsDXOptimal(_In_ IUnknown *pDeviceManager, _Out_ BOOL *pIsOptimal) +{ + HRESULT hr = S_OK; + ComPtr<IMFDXGIDeviceManager> spDXGIDeviceManager = nullptr; + ComPtr<ID3D11Device> spD3D11 = nullptr; + ComPtr<ID3D11VideoDevice> spVideoDevice = nullptr; + HANDLE hDevice = NULL; + BOOL locked = FALSE; + + *pIsOptimal = false; + DMFTCHECKNULL_GOTO( pDeviceManager, done, E_INVALIDARG ); + DMFTCHECKHR_GOTO( pDeviceManager->QueryInterface(IID_PPV_ARGS( &spDXGIDeviceManager )), done ); + DMFTCHECKHR_GOTO( spDXGIDeviceManager->OpenDeviceHandle( &hDevice ), done ); + DMFTCHECKHR_GOTO( spDXGIDeviceManager->LockDevice( hDevice, IID_PPV_ARGS( &spD3D11 ), TRUE), done ); + locked = TRUE; + DMFTCHECKHR_GOTO( spD3D11.As(&spVideoDevice), done ); + + if (spD3D11->GetFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + if (FAILED(CheckDX9RotationSupport(spVideoDevice.Get()))) + { + goto done; + } + } + *pIsOptimal = TRUE; +done: + if (hDevice) + { + if (locked) + { + spDXGIDeviceManager->UnlockDevice(hDevice, false); + } + spDXGIDeviceManager->CloseDeviceHandle(hDevice); + } + return hr; +} + + +// +// Used to check if the pin is a custom pin or not!! +// + +STDMETHODIMP CheckCustomPin( + _In_ CInPin * pPin, + _Inout_ PBOOL pIsCustom + ) +{ + HRESULT hr = S_OK; + DMFTCHECKNULL_GOTO( pPin, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO( pIsCustom, done, E_INVALIDARG); + + *pIsCustom = false; + +#if defined _CPPRTTI + if (dynamic_cast<CCustomPin*>(pPin) != nullptr) + { + *pIsCustom = true; + } + else +#endif + { + GUID categoryGUID = GUID_NULL; + if (SUCCEEDED(pPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &categoryGUID)) + && IsEqualCLSID(categoryGUID, AVSTREAM_CUSTOM_PIN_IMAGE)) + { + *pIsCustom = true; + } + } +done: + return hr; +} + diff --git a/AVStream/sampledevicemft/stdafx.h b/AVStream/sampledevicemft/stdafx.h new file mode 100644 index 00000000..9f4bab9f --- /dev/null +++ b/AVStream/sampledevicemft/stdafx.h @@ -0,0 +1,39 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once + + +#include <SDKDDKVer.h> +#include <windows.h> +#include <winnt.h> +#include <tchar.h> +#include <comdef.h> +#include <initguid.h> +#include <ks.h> +#include <ksmedia.h> +#include <Strsafe.h> +#include <wchar.h> +#include <stdio.h> +#include <assert.h> +#include <mfidl.h> +#include <wincodec.h> +#include <mfapi.h> +#include <mftransform.h> +#include <mfidl.h> +#include <mferror.h> +#include <mftransform.h> +#include <time.h> +#include <initguid.h> +#include <d3d9.h> +#include <dxva2api.h> +#include <d3d11.h> +#include <mfcaptureengine.h> +#include <new> +#include <vector> +#include <map> +using namespace std; +#include <Windows.Foundation.h> +#include <wrl\client.h> +using namespace ABI::Windows::Foundation; +using namespace Microsoft::WRL; diff --git a/AVStream/sampledevicemft/stdafxsrc.cpp b/AVStream/sampledevicemft/stdafxsrc.cpp new file mode 100644 index 00000000..1577c4e3 --- /dev/null +++ b/AVStream/sampledevicemft/stdafxsrc.cpp @@ -0,0 +1 @@ +#include "stdafx.h"
\ No newline at end of file |
