diff options
| author | Adonais Romero González <[email protected]> | 2024-05-06 16:21:31 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-05-06 16:21:31 -0700 |
| commit | a74a241c664c4e1d7c0838287b34076c19d9858a (patch) | |
| tree | 6ff7562612967b122acf8acf8a69c4dcfd5905db /avstream/avscamera/DMFT | |
| parent | def8e8e34ed2b7b1deb2fc9112ac4255f1a0f2ba (diff) | |
| parent | 15477ce52bbb6b42ca591ecdfb484cac089f89ab (diff) | |
Merge develop changes prior to upcoming WDK release (May 2024)
Diffstat (limited to 'avstream/avscamera/DMFT')
| -rw-r--r-- | avstream/avscamera/DMFT/AvsCameraDMFT.cpp | 1311 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/AvsCameraDMFT.h | 334 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj | 250 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters | 57 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp | 805 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/Source.def | 5 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/basepin.cpp | 625 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/basepin.h | 568 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/common.h | 360 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/dllmain.cpp | 354 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/mftpeventgenerator.cpp | 234 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/mftpeventgenerator.h | 94 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/packages.config | 4 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/stdafx.h | 47 | ||||
| -rw-r--r-- | avstream/avscamera/DMFT/stdafxsrc.cpp | 4 |
15 files changed, 5052 insertions, 0 deletions
diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp new file mode 100644 index 00000000..e12cff65 --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp @@ -0,0 +1,1311 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "stdafx.h" +#ifdef MF_WPP +#include "AvsCameraDMFT.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif +// +// This DeviceMFT is a stripped down implementation of the device MFT Sample present in the sample Repo +// The original DMFT is present at https://github.com/microsoft/Windows-driver-samples/tree/main/avstream/sampledevicemft +// +CMultipinMft::CMultipinMft() +: m_nRefCount( 0 ), + m_InputPinCount( 0 ), + m_OutputPinCount( 0 ), + m_dwWorkQueueId ( MFASYNC_CALLBACK_QUEUE_MULTITHREADED ), + m_lWorkQueuePriority ( 0 ), + m_spAttributes( nullptr ), + m_spSourceTransform( nullptr ), + m_SymbolicLink(nullptr) + +{ + HRESULT hr = S_OK; + ComPtr<IMFAttributes> pAttributes = nullptr; + MFCreateAttributes( &pAttributes, 0 ); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE ),done); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ),done); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE ), done); + DMFTCHECKHR_GOTO(pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" ),done); + m_spAttributes = pAttributes; +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); +} + +CMultipinMft::~CMultipinMft( ) +{ + m_OutPins.clear(); + SAFE_ARRAYDELETE(m_SymbolicLink); + m_spSourceTransform = nullptr; + +} + +IFACEMETHODIMP_(ULONG) CMultipinMft::AddRef( + void + ) +{ + return InterlockedIncrement(&m_nRefCount); +} + +IFACEMETHODIMP_(ULONG) CMultipinMft::Release( + void + ) +{ + ULONG uCount = InterlockedDecrement(&m_nRefCount); + + if ( uCount == 0 ) + { + delete this; + } + return uCount; +} + +IFACEMETHODIMP CMultipinMft::QueryInterface( + _In_ REFIID iid, + _COM_Outptr_ void** ppv + ) +{ + + HRESULT hr = S_OK; + *ppv = NULL; + + if ((iid == __uuidof(IMFDeviceTransform)) || (iid == __uuidof(IUnknown))) + { + *ppv = static_cast< IMFDeviceTransform* >(this); + } + else if ( iid == __uuidof( IMFMediaEventGenerator ) ) + { + *ppv = static_cast< IMFMediaEventGenerator* >(this); + } + else if ( iid == __uuidof( IMFShutdown ) ) + { + *ppv = static_cast< IMFShutdown* >( this ); + } + else if ( iid == __uuidof( IKsControl ) ) + { + *ppv = static_cast< IKsControl* >( this ); + } + else if ( iid == __uuidof( IMFRealTimeClientEx ) ) + { + *ppv = static_cast< IMFRealTimeClientEx* >( this ); + } + else + { + hr = E_NOINTERFACE; + goto done; + } + AddRef(); +done: + return hr; +} + +/*++ + Description: + This function is the entry point of the transform + The following things may be initialized here + 1) Query for MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL on the attributes supplied + 2) From the IUnknown acquired get the IMFTransform interface. + 3) Get the stream count.. The output streams are of consequence to the tranform. + The input streams should correspond to the output streams exposed by the source transform + acquired from the Attributes supplied. + 4) Get the IKSControl which is used to send KSPROPERTIES, KSEVENTS and KSMETHODS to the driver for the filer level. Store it in your filter class + 5) Get the OutPutStreamAttributes for the output pins of the source transform. This can further be used to QI and acquire + the IKSControl related to the specific pin. This can be used to send PIN level KSPROPERTIES, EVENTS and METHODS to the pins + 6) Create the output pins + +--*/ + +IFACEMETHODIMP CMultipinMft::InitializeTransform ( + _In_ IMFAttributes *pAttributes + ) +{ + HRESULT hr = S_OK; + ComPtr<IUnknown> spFilterUnk = nullptr; + DWORD *pcInputStreams = NULL, *pcOutputStreams = NULL; + DWORD inputStreams = 0; + DWORD outputStreams = 0; + GUID* outGuids = NULL; + GUID streamCategory = GUID_NULL; + ULONG ulOutPinIndex = 0; + UINT32 uiSymLinkLen = 0; + DMFTCHECKNULL_GOTO( pAttributes, done, E_INVALIDARG ); + // + // The attribute passed with MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL is the source transform. This generally represents a filter + // This needs to be stored so that we know the device properties. We cache it. We query for the IKSControl which is used to send + // controls to the driver. + // + DMFTCHECKHR_GOTO( pAttributes->GetUnknown( MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL,IID_PPV_ARGS( &spFilterUnk ) ),done ); + + if (SUCCEEDED(pAttributes->GetStringLength(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &uiSymLinkLen))) // Not available prior to RS5 + { + m_SymbolicLink = new (std::nothrow) WCHAR[++uiSymLinkLen]; + DMFTCHECKNULL_GOTO(m_SymbolicLink, done, E_OUTOFMEMORY); + DMFTCHECKHR_GOTO(pAttributes->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, m_SymbolicLink, uiSymLinkLen, &uiSymLinkLen), done); + } + + DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done ); + + DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done ); + + DMFTCHECKHR_GOTO(m_spSourceTransform->GetStreamCount(&inputStreams, &outputStreams), done); + + spFilterUnk = nullptr; + + // + //The number of input pins created by the device transform should match the pins exposed by + //the source transform i.e. outputStreams from SourceTransform or DevProxy = Input pins of the Device MFT + // + + if ( inputStreams > 0 || outputStreams > 0 ) + { + pcInputStreams = new (std::nothrow) DWORD[ inputStreams ]; + DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY); + + pcOutputStreams = new (std::nothrow) DWORD[ outputStreams ]; + DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY ); + + DMFTCHECKHR_GOTO( m_spSourceTransform->GetStreamIDs( inputStreams, pcInputStreams, + outputStreams, + pcOutputStreams ),done ); + + for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ ) + { + ComPtr<IMFAttributes> spInAttributes; + ComPtr<CInPin> spInPin; + + DMFTCHECKHR_GOTO(m_spSourceTransform->GetOutputStreamAttributes(ulIndex, &spInAttributes),done); + spInPin = new (std::nothrow) CInPin(spInAttributes.Get(), ulIndex, this); + DMFTCHECKNULL_GOTO(spInPin.Get(), done, E_OUTOFMEMORY); + + hr = ExceptionBoundary([&]() + { + m_InPins.push_back(spInPin.Get()); + }); + DMFTCHECKHR_GOTO(hr, done); + DMFTCHECKHR_GOTO(spInPin->Init(m_spSourceTransform.Get()), done); + } + + // + // Create one on one mapping + // + for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++) + { + + ComPtr<CInPin> spInPin = (CInPin*)m_InPins[ulIndex].Get(); + + if (spInPin.Get()) + { + ComPtr<COutPin> spOutPin; + ComPtr<IKsControl> spKscontrol; + GUID pinGuid = GUID_NULL; + UINT32 uiFrameSourceType = 0; + + DMFTCHECKHR_GOTO(spInPin.As(&spKscontrol), done); // Grab the IKSControl off the input pin + DMFTCHECKHR_GOTO(spInPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinGuid), done); // Get the Stream Category. Advertise on the output pin + + + spOutPin = new (std::nothrow) COutPin( + ulIndex, + this, + spKscontrol.Get()); // Create the output pin + DMFTCHECKNULL_GOTO(spOutPin.Get(), done, E_OUTOFMEMORY); + + DMFTCHECKHR_GOTO(spOutPin->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, pinGuid), done); // Advertise the Stream category to the Pipeline + DMFTCHECKHR_GOTO(spOutPin->SetUINT32(MF_DEVICESTREAM_STREAM_ID, ulIndex), done); + if (SUCCEEDED(spInPin->GetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, &uiFrameSourceType))) + { + DMFTCHECKHR_GOTO(spOutPin->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, uiFrameSourceType), done); + } + + hr = BridgeInputPinOutputPin(spInPin.Get(), spOutPin.Get()); + if (SUCCEEDED(hr)) + { + DMFTCHECKHR_GOTO(ExceptionBoundary([&]() + { + m_OutPins.push_back(spOutPin.Get()); + }), done); + ulOutPinIndex++; + } + 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 + m_InPins.clear(); + m_OutPins.clear(); + // + // Simply clear the custom pins since the input pins must have deleted the pin + // + m_spSourceTransform = nullptr; + m_spIkscontrol = nullptr; + } + return hr; +} + + +IFACEMETHODIMP CMultipinMft::SetWorkQueueEx( + _In_ DWORD dwWorkQueueId, + _In_ LONG lWorkItemBasePriority + ) +/*++ + Description: + + Implements IMFRealTimeClientEx::SetWorkQueueEx function + +--*/ +{ + CAutoLock lock( m_critSec ); + // + // Cache the WorkQueuId and WorkItemBasePriority. This is called once soon after the device MFT is initialized + // + m_dwWorkQueueId = dwWorkQueueId; + m_lWorkQueuePriority = lWorkItemBasePriority; + // Set it on the pins + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++) + { + m_InPins[dwIndex]->SetWorkQueue(dwWorkQueueId); + } + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++) + { + m_OutPins[dwIndex]->SetWorkQueue(dwWorkQueueId); + } + return S_OK; + +} + +// +// IMFDeviceTransform functions +// +IFACEMETHODIMP CMultipinMft::GetStreamCount( + _Inout_ DWORD *pdwInputStreams, + _Inout_ DWORD *pdwOutputStreams + ) +/*++ + Description: Implements IMFTransform::GetStreamCount function +--*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + DMFTCHECKNULL_GOTO(pdwInputStreams, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pdwOutputStreams, done, E_INVALIDARG); + *pdwInputStreams = m_InputPinCount; + *pdwOutputStreams = m_OutputPinCount; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); +done: + return hr; +} + +// +//Doesn't strictly conform to the GetStreamIDs on IMFTransform Interface! +// +IFACEMETHODIMP CMultipinMft::GetStreamIDs( + _In_ DWORD dwInputIDArraySize, + _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs, + _In_ DWORD dwOutputIDArraySize, + _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)), + _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs + ) +/*++ + Description: + Implements IMFTransform::GetStreamIDs function +--*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + if ( ( dwInputIDArraySize < m_InputPinCount ) && ( dwOutputIDArraySize < m_OutputPinCount ) ) + { + hr = MF_E_BUFFERTOOSMALL; + goto done; + } + + if ( dwInputIDArraySize ) + { + DMFTCHECKNULL_GOTO( pdwInputIDs, done, E_POINTER ); + for ( DWORD dwIndex = 0; dwIndex < ((dwInputIDArraySize > m_InputPinCount) ? m_InputPinCount: + dwInputIDArraySize); dwIndex++ ) + { + pdwInputIDs[ dwIndex ] = ( m_InPins[dwIndex] )->streamId(); + } + } + + if ( dwOutputIDArraySize ) + { + DMFTCHECKNULL_GOTO( pdwOutputIDs, done, E_POINTER ); + for ( DWORD dwIndex = 0; dwIndex < ((dwOutputIDArraySize > m_OutputPinCount)? m_OutputPinCount: + dwOutputIDArraySize); dwIndex++ ) + { + pdwOutputIDs[ dwIndex ] = (m_OutPins[ dwIndex ])->streamId(); + } + } +done: + return hr; +} + +/*++ +Name: CMultipinMft::GetInputAvailableType +Description: +Implements IMFTransform::GetInputAvailableType function. This function +gets the media type supported by the specified stream based on the +index dwTypeIndex. +--*/ +IFACEMETHODIMP CMultipinMft::GetInputAvailableType( + _In_ DWORD dwInputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType + ) +{ + HRESULT hr = S_OK; + + ComPtr<CInPin> spiPin = GetInPin( dwInputStreamID ); + DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO( spiPin, done, MF_E_INVALIDSTREAMNUMBER ); + + *ppMediaType = nullptr; + + hr = spiPin->GetOutputAvailableType( dwTypeIndex,ppMediaType ); + + if (FAILED(hr)) + { + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!", + dwInputStreamID, + dwTypeIndex, + hr); + } + +done: + return hr; +} + +IFACEMETHODIMP CMultipinMft::GetOutputAvailableType( + _In_ DWORD dwOutputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType + ) +/*++ + Description: + + Implements IMFTransform::GetOutputAvailableType function. This function + gets the media type supported by the specified stream based on the + index dwTypeIndex. + +--*/ +{ + HRESULT hr = S_OK; + CAutoLock Lock(m_critSec); + + ComPtr<COutPin> spoPin = GetOutPin( dwOutputStreamID ); + + DMFTCHECKNULL_GOTO( spoPin.Get(), done, MF_E_INVALIDSTREAMNUMBER ); + DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG); + + *ppMediaType = nullptr; + + hr = spoPin->GetOutputAvailableType( dwTypeIndex, ppMediaType ); + + if ( FAILED( hr ) ) + { + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!", + dwOutputStreamID, + dwTypeIndex, + hr ); + } + +done: + return hr; +} + +IFACEMETHODIMP 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; +} + +IFACEMETHODIMP CMultipinMft::GetOutputCurrentType( + _In_ DWORD dwOutputStreamID, + _Out_ IMFMediaType** ppMediaType + ) +/*++ + Description: + + Implements IMFTransform::GetOutputCurrentType function. This function + returns the current media type set on the specified stream. + +--*/ +{ + HRESULT hr = S_OK; + ComPtr<COutPin> spoPin; + CAutoLock lock( m_critSec ); + + DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG ); + + *ppMediaType = nullptr; + + spoPin = GetOutPin( dwOutputStreamID ); + + DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER ); + + DMFTCHECKHR_GOTO(spoPin->getMediaType( ppMediaType ),done ); + + DMFTCHECKNULL_GOTO( *ppMediaType, done, MF_E_TRANSFORM_TYPE_NOT_SET ); + +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + + +IFACEMETHODIMP 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; +} + + + +IFACEMETHODIMP CMultipinMft::ProcessMessage( + _In_ MFT_MESSAGE_TYPE eMessage, + _In_ ULONG_PTR ulParam + ) +/*++ + Description: + + Implements IMFTransform::ProcessMessage function. This function + processes messages coming to the MFT. + +--*/ +{ + HRESULT hr = S_OK; + + UNREFERENCED_PARAMETER(ulParam); + + CAutoLock _lock( m_critSec ); + + switch ( eMessage ) + { + case MFT_MESSAGE_COMMAND_FLUSH: + // + // This is MFT wide flush.. Flush all output pins + // + (VOID)FlushAllStreams(); + break; + case MFT_MESSAGE_COMMAND_DRAIN: + // + // There is no draining for Device MFT. Just kept here for reference + // + break; + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + // + // No op for device MFTs + // + break; + case MFT_MESSAGE_SET_D3D_MANAGER: + { + if ( ulParam ) + { + ComPtr< IDirect3DDeviceManager9 > spD3D9Manager; + ComPtr< IMFDXGIDeviceManager > spDXGIManager; + + hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spD3D9Manager ) ); + if ( SUCCEEDED( hr ) ) + { + m_spDeviceManagerUnk = ( IUnknown* )ulParam; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IDirect3DDeviceManager9 %p, is passed", spD3D9Manager.Get() ); + } + else + { + hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spDXGIManager ) ); + if ( SUCCEEDED(hr) ) + { + m_spDeviceManagerUnk = (IUnknown*)ulParam; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IMFDXGIDeviceManager %p, is passed", spDXGIManager.Get()); + } + } + } + else + { + m_spDeviceManagerUnk = nullptr; + hr = S_OK; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC!IDirect3DDeviceManager9 was not passed in"); + } + // + // set it on the pins. Can happen anytime + // + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++) + { + m_InPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get()); + } + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++) + { + m_OutPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get()); + } + } + break; + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + { + SetStreamingState( DeviceStreamState_Run ); + } + break; + case MFT_MESSAGE_NOTIFY_END_STREAMING: + { + SetStreamingState(DeviceStreamState_Stop); + } + break; + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + { + SetStreamingState(DeviceStreamState_Stop); + } + break; + default: + ; + } + + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + +IFACEMETHODIMP 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 ); + CAutoLock lock(m_critSec); + + ComPtr<CInPin> spInPin = GetInPin( dwInputStreamID ); + DMFTCHECKNULL_GOTO(spInPin, done, MF_E_INVALIDSTREAMNUMBER); + + if ( !IsStreaming() ) + { + goto done; + } + + DMFTCHECKHR_GOTO(spInPin->SendSample( pSample ), done ); +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + // + //@@@@ README : There is a bug in the sample that the device transform manager which manages the + // device MFT does not release the sample after passing it to Device MFT in processInput like it should. The + // Device MFT therefore unfortunately has to make sure that the sample that leaves processoutput has a reference count of 1 + // + SAFE_RELEASE(pSample); + return hr; + +} + +IFACEMETHODIMP CMultipinMft::ProcessOutput( + _In_ DWORD dwFlags, + _In_ DWORD cOutputBufferCount, + _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, + _Out_ DWORD *pdwStatus +) +/*++ +Description: + +Implements IMFTransform::ProcessOutput function. This is called by the DTM when +the DT indicates it has samples to give. The DTM will send enough MFT_OUTPUT_DATA_BUFFER +pointers to be filled up as is the number of output pins available. The DT should traverse its +output pins and populate the corresponding MFT_OUTPUT_DATA_BUFFER with the samples available + +--*/ +{ + HRESULT hr = S_OK; + BOOL gotOne = false; + ComPtr<COutPin> spOpin; + UNREFERENCED_PARAMETER( dwFlags ); + + if (cOutputBufferCount > m_OutputPinCount ) + { + DMFTCHECKHR_GOTO( E_INVALIDARG, done ); + } + *pdwStatus = 0; + + for ( DWORD i = 0; i < cOutputBufferCount; i++ ) + { + DWORD dwStreamID = pOutputSamples[i].dwStreamID; + { + CAutoLock _lock(m_critSec); + spOpin = nullptr; + spOpin = GetOutPin(dwStreamID); + GUID pinGuid = GUID_NULL; + DMFTCHECKNULL_GOTO(spOpin.Get(), done, E_INVALIDARG); + } + if ( SUCCEEDED(spOpin->ProcessOutput( dwFlags, &pOutputSamples[i], + pdwStatus ) ) ) + { + if (pOutputSamples[i].pSample) + { + ProcessMetadata(pOutputSamples[i].pSample); + } + gotOne = true; + } + } + if (gotOne) + { + hr = S_OK; + } + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +IFACEMETHODIMP CMultipinMft::GetInputStreamAttributes( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes + ) +/*++ + Description: + + Implements IMFTransform::GetInputStreamAttributes function. This function + gets the specified input stream's attributes. + +--*/ +{ + HRESULT hr = S_OK; + ComPtr<CInPin> spIPin; + CAutoLock Lock(m_critSec); + + DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG ); + *ppAttributes = nullptr; + + spIPin = GetInPin( dwInputStreamID ); + + DMFTCHECKNULL_GOTO(spIPin, done, E_INVALIDARG ); + + hr = spIPin->getPinAttributes(ppAttributes); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +IFACEMETHODIMP CMultipinMft::GetOutputStreamAttributes( + _In_ DWORD dwOutputStreamID, + _Out_ IMFAttributes** ppAttributes + ) +/*++ + Description: + + Implements IMFTransform::GetOutputStreamAttributes function. This function + gets the specified output stream's attributes. + +--*/ +{ + HRESULT hr = S_OK; + ComPtr<COutPin> spoPin; + CAutoLock Lock(m_critSec); + + DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG); + + *ppAttributes = nullptr; + + spoPin = GetOutPin(dwOutputStreamID); + + DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG ); + + DMFTCHECKHR_GOTO(spoPin->getPinAttributes(ppAttributes), done ); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +_Requires_no_locks_held_ +IFACEMETHODIMP 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; + ComPtr<CInPin> spiPin = GetInPin(dwStreamID); + CAutoLock Lock(m_critSec); + + DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER); + + DMFTCHECKHR_GOTO(spiPin->SetInputStreamState(pMediaType, value, dwFlags),done); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +IFACEMETHODIMP CMultipinMft::GetInputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value + ) +{ + HRESULT hr = S_OK; + ComPtr<CInPin> piPin = GetInPin(dwStreamID); + + DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER); + + *value = piPin->GetState(); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +IFACEMETHODIMP 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; +} + +IFACEMETHODIMP CMultipinMft::GetOutputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *pState + ) + /*++ + Description: + + Implements IMFdeviceTransform::GetOutputStreamState function. + Gets the output stream state. + Called by the DTM to checks states. Atomic operation. needs a lock + --*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + + ComPtr<COutPin> spoPin = GetOutPin(dwStreamID); + DMFTCHECKNULL_GOTO(pState, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER); + *pState = spoPin->GetState(); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +IFACEMETHODIMP 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; + CAutoLock lock(m_critSec); + ComPtr<CInPin> spiPin = GetInPin(dwStreamID); + DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER); + hr = spiPin->GetInputStreamPreferredState(value, ppMediaType); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +IFACEMETHODIMP 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; +} + +IFACEMETHODIMP CMultipinMft::FlushOutputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::FlushOutputStream function. + Called by the DTM to flush streams + --*/ +{ + + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwFlags); + CAutoLock Lock(m_critSec); + + ComPtr<COutPin> spoPin = GetOutPin(dwStreamIndex); + DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG); + DeviceStreamState oldState = spoPin->SetState(DeviceStreamState_Disabled); + DMFTCHECKHR_GOTO(spoPin->FlushQueues(),done); + spoPin->SetState(oldState); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +/*++ + Description: + + Called when the Device Transform gets a MFT_MESSAGE_COMMAND_FLUSH. We drain all the queues. + This is called in device source when the source gets end of streaming. + --*/ +IFACEMETHODIMP_(VOID) CMultipinMft::FlushAllStreams( + VOID + ) +{ + DeviceStreamState oldState; + CAutoLock Lock(m_critSec); + for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ ) + { + ComPtr<COutPin> spoPin = (COutPin *)m_OutPins[dwIndex].Get(); + oldState = spoPin->SetState(DeviceStreamState_Disabled); + spoPin->FlushQueues(); + // + //Restore state + // + spoPin->SetState(oldState); + } +} + +// +// IKsControl interface functions +// +IFACEMETHODIMP 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; + + DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty, + ulPropertyLength, + pvPropertyData, + ulDataLength, + pulBytesReturned),done); +done: + return hr; +} + +IFACEMETHODIMP CMultipinMft::KsMethod( + _In_reads_bytes_(ulPropertyLength) PKSMETHOD pMethod, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pulBytesReturned + ) + /*++ + Description: + + Implements IKSProperty::KsMethod function. We can trap ksmethod calls here. + --*/ +{ + HRESULT hr = S_OK; + + DMFTCHECKHR_GOTO(m_spIkscontrol->KsMethod( + pMethod, + ulPropertyLength, + pvPropertyData, + ulDataLength, + pulBytesReturned + ), done); +done: + return hr; +} + +IFACEMETHODIMP 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; + // Handle the events here if you want, This sample passes the events to the driver + DMFTCHECKHR_GOTO(m_spIkscontrol->KsEvent(pEvent, + ulEventLength, + pEventData, + ulDataLength, + pBytesReturned), done); +done: + return hr; +} + +// +// HELPER FUNCTIONS +// + +// +// A lock here could mean a deadlock because this will be called when the lock is already held +// in another thread. +// +CInPin* CMultipinMft::GetInPin( + _In_ DWORD dwStreamId +) +{ + CInPin *inPin = NULL; + for (DWORD dwIndex = 0, dwSize = (DWORD)m_InPins.size(); dwIndex < dwSize; dwIndex++) + { + inPin = (CInPin *)m_InPins[dwIndex].Get(); + if (dwStreamId == inPin->streamId()) + { + break; + } + inPin = NULL; + } + return inPin; +} + +COutPin* CMultipinMft::GetOutPin( + _In_ DWORD dwStreamId + ) +{ + COutPin *outPin = NULL; + for ( DWORD dwIndex = 0, dwSize = (DWORD) m_OutPins.size(); dwIndex < dwSize; dwIndex++ ) + { + outPin = ( COutPin * )m_OutPins[ dwIndex ].Get(); + + if ( dwStreamId == outPin->streamId() ) + { + break; + } + + outPin = NULL; + } + + return outPin; +} +_Requires_lock_held_(m_Critsec) +HRESULT CMultipinMft::GetConnectedInpin(_In_ ULONG ulOutpin, _Out_ ULONG &ulInPin) +{ + HRESULT hr = S_OK; + map<int, int>::iterator it = m_outputPinMap.find(ulOutpin); + if (it != m_outputPinMap.end()) + { + ulInPin = it->second; + } + else + { + hr = MF_E_INVALIDSTREAMNUMBER; + } + return hr; +} + +// +// The Below function changes media type on the pins exposed by device MFT +// +__requires_lock_held(m_critSec) +HRESULT CMultipinMft::ChangeMediaTypeEx( + _In_ ULONG pinId, + _In_opt_ IMFMediaType *pMediaType, + _In_ DeviceStreamState reqState +) +{ + HRESULT hr = S_OK; + ComPtr<COutPin> spoPin = GetOutPin(pinId); + ComPtr<CInPin> spinPin; + DeviceStreamState oldOutPinState, oldInputStreamState, newOutStreamState, newRequestedInPinState; + ComPtr<IMFMediaType> pFullType, pInputMediaType; + ULONG ulInPinId = 0; + DWORD dwFlags = 0; + + + DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG); + + if (pMediaType) + { + if (!spoPin->IsMediaTypeSupported(pMediaType, &pFullType)) + { + DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done); + } + } + + DMFTCHECKHR_GOTO(GetConnectedInpin(pinId, ulInPinId), done); + spinPin = GetInPin(ulInPinId); // Get the input pin + + (VOID)spinPin->getMediaType(&pInputMediaType); + oldInputStreamState = spinPin->SetState(DeviceStreamState_Disabled); // Disable input pin + oldOutPinState = spoPin->SetState(DeviceStreamState_Disabled); // Disable output pin + (void)spoPin->FlushQueues(); // Flush the output queues + (void)spinPin->FlushQueues(); // Flush the input queues + newOutStreamState = pinStateTransition[oldOutPinState][reqState]; // New state needed + + // The Old input and the output pin states should be the same + newRequestedInPinState = newOutStreamState; + + if ((newOutStreamState != oldOutPinState) /*State change*/ + ||((pFullType.Get() != nullptr) && (pInputMediaType.Get()!=nullptr) && (S_OK != (pFullType->IsEqual(pInputMediaType.Get(), &dwFlags)))) /*Media Types dont match*/ + ||((pFullType == nullptr)||(pInputMediaType == nullptr))/*Either one of the mediatypes is null*/ + ) + { + // + // State has change or media type has changed so we need to change the media type on the + // underlying kernel pin + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Changing Mediatype on the input "); + spinPin->setPreferredMediaType(pFullType.Get()); + spinPin->setPreferredStreamState(newRequestedInPinState); + // Let the pipline know that the input needs to be changed. + SendEventToManager(METransformInputStreamStateChanged, GUID_NULL, spinPin->streamId()); + // + // The media type will be set on the input pin by the time we return from the wait + // + m_critSec.Unlock(); + hr = spinPin->WaitForSetInputPinMediaChange(); + m_critSec.Lock(); + // Change the media type on the output.. + DMFTCHECKHR_GOTO(spoPin->ChangeMediaTypeFromInpin( pMediaType , reqState), done); + // + // Notify the pipeline that the output stream media type has changed + // + DMFTCHECKHR_GOTO(SendEventToManager(MEUnknown, MEDeviceStreamCreated, spoPin->streamId()), done); + spoPin->SetFirstSample(TRUE); + } + else + { + // Restore back old states as we have nothing to do + spinPin->SetState(oldInputStreamState); + spoPin->SetState(oldOutPinState); + } + + +done: + return hr; +} + +// +// The below function sends events to the pipeline. +// + +HRESULT CMultipinMft::SendEventToManager( + _In_ MediaEventType eventType, + _In_ REFGUID pGuid, + _In_ UINT32 context + ) + /*++ + Description: + Used to send the event to DTM. + --*/ + { + HRESULT hr = S_OK; + ComPtr<IMFMediaEvent> pEvent = nullptr; + + DMFTCHECKHR_GOTO(MFCreateMediaEvent(eventType, pGuid, S_OK, NULL, &pEvent ),done); + DMFTCHECKHR_GOTO(pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, (ULONG)context),done); + DMFTCHECKHR_GOTO(QueueEvent(pEvent.Get()),done); + done: + + return hr; + } +/*++ +Description: +This function connects the input and output pins. +Any media type filtering can happen here +--*/ +HRESULT CMultipinMft::BridgeInputPinOutputPin( + _In_ CInPin* piPin, + _In_ COutPin* poPin + ) +{ + HRESULT hr = S_OK; + ULONG ulIndex = 0; + ULONG ulAddedMediaTypeCount = 0; + ComPtr<IMFMediaType> spMediaType; + + DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG ); + DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG ); + + while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, spMediaType.ReleaseAndGetAddressOf() ))) + { + DMFTCHECKHR_GOTO(hr = poPin->AddMediaType(NULL, spMediaType.Get() ), done ); + ulAddedMediaTypeCount++; + } + + if (ulAddedMediaTypeCount == 0) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Make Sure Pin %d has one media type exposed ", piPin->streamId()); + DMFTCHECKHR_GOTO( MF_E_INVALID_STREAM_DATA, done ); + } + // + //Add the Input Pin to the output Pin + // + DMFTCHECKHR_GOTO(poPin->AddPin(piPin->streamId()), done); + hr = ExceptionBoundary([&](){ + // + // Add the output pin to the input pin. + // Create the pin map. So that we know which pin input pin is connected to which output pin + // + piPin->ConnectPin(poPin); + m_outputPinMap.insert(std::pair< int, int >(poPin->streamId(), piPin->streamId())); + }); +done: + // + //Failed adding media types + // + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + } + return hr; +} + +// +// IMFShutdown interface functions +// + +/*++ +Description: +Implements the Shutdown from IMFShutdown +--*/ +IFACEMETHODIMP CMultipinMft::Shutdown( + void + ) +{ + CAutoLock Lock(m_critSec); + + for (ULONG ulIndex = 0, ulSize = (ULONG)m_InPins.size(); ulIndex < ulSize; ulIndex++ ) + { + CInPin *pInPin = static_cast<CInPin *>(m_InPins[ulIndex].Get()); + + // Deref on the connected outpins to break reference loop + (VOID)pInPin->ShutdownPin(); + } + return ShutdownEventGenerator(); +} + +// +// Static method to create an instance of the MFT. +// +HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT) +{ + HRESULT hr = S_OK; + ComPtr<CMultipinMft> spMFT; + DMFTCHECKNULL_GOTO(ppMFT, done, E_POINTER); + spMFT = new (std::nothrow) CMultipinMft(); + DMFTCHECKNULL_GOTO(spMFT.Get(), done, E_OUTOFMEMORY); + + DMFTCHECKHR_GOTO(spMFT->QueryInterface(iid, ppMFT), done); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.h b/avstream/avscamera/DMFT/AvsCameraDMFT.h new file mode 100644 index 00000000..27b8607b --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.h @@ -0,0 +1,334 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#pragma once +#include "common.h" +#include "mftpeventgenerator.h" +#include "basepin.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; +class CPinCreationFactory; +// +// CMultipinMft class: +// Implements a device proxy MFT. +// +class CMultipinMft : + public IMFDeviceTransform + , public IMFShutdown + , public CMediaEventGenerator + , public IMFRealTimeClientEx + , public IKsControl + , public CDMFTModuleLifeTimeManager +{ + friend class CPinCreationFactory; +public: + CMultipinMft( + void ); + + virtual ~CMultipinMft(); + + // + // IUnknown + // + IFACEMETHODIMP_(ULONG) AddRef( + void ); + + IFACEMETHODIMP_(ULONG) Release( + void ); + + IFACEMETHODIMP QueryInterface( + _In_ REFIID iid, + _COM_Outptr_ void** ppv); + + + // + // IMFDeviceTransform functions + // + IFACEMETHODIMP GetStreamCount ( + _Inout_ DWORD *pdwInputStreams, + _Inout_ DWORD *pdwOutputStreams); + + + IFACEMETHODIMP 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 + ); + + IFACEMETHODIMP GetInputStreamAttributes( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes); + + IFACEMETHODIMP GetOutputStreamAttributes( + _In_ DWORD dwOutputStreamID, + _Out_ IMFAttributes** ppAttributes); + + IFACEMETHODIMP GetInputAvailableType( + _In_ DWORD dwInputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppType); + + IFACEMETHODIMP GetOutputAvailableType( + _In_ DWORD dwOutputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType); + + IFACEMETHODIMP GetInputCurrentType( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType); + + IFACEMETHODIMP GetOutputCurrentType( + _In_ DWORD dwOutputStreamID, + _Out_ IMFMediaType** ppMediaType); + + IFACEMETHODIMP ProcessMessage( + _In_ MFT_MESSAGE_TYPE eMessage, + _In_ ULONG_PTR ulParam ); + + IFACEMETHODIMP ProcessEvent( + _In_ DWORD dwInputStreamID, + _In_ IMFMediaEvent *pEvent); + + + IFACEMETHODIMP ProcessInput( + _In_ DWORD dwInputStreamID, + _In_ IMFSample* pSample, + _In_ DWORD dwFlags ); + + IFACEMETHODIMP ProcessOutput( + _In_ DWORD dwFlags, + _In_ DWORD cOutputBufferCount, + _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, + _Out_ DWORD *pdwStatus ); + + // + // IMFRealTimeClientEx + // + IFACEMETHODIMP RegisterThreadsEx( + _Inout_ DWORD* pdwTaskIndex, + _In_ LPCWSTR wszClassName, + _In_ LONG lBasePriority ) + { + UNREFERENCED_PARAMETER(pdwTaskIndex); + UNREFERENCED_PARAMETER(wszClassName); + UNREFERENCED_PARAMETER(lBasePriority); + return S_OK; + } + + IFACEMETHODIMP UnregisterThreads() + { + return S_OK; + } + + IFACEMETHODIMP SetWorkQueueEx( + _In_ DWORD dwWorkQueueId, + _In_ LONG lWorkItemBasePriority ); + + // + // IMFShutdown + // + IFACEMETHODIMP Shutdown( + void ); + + IFACEMETHODIMP GetShutdownStatus( + MFSHUTDOWN_STATUS *pStatus) + { + UNREFERENCED_PARAMETER(pStatus); + return(m_eShutdownStatus); + }; + + // + // IMFDeviceTransform function declarations + // + IFACEMETHODIMP InitializeTransform( + _In_ IMFAttributes *pAttributes ); + + _Requires_no_locks_held_ + IFACEMETHODIMP SetInputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags ); + + IFACEMETHODIMP GetInputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value ); + + IFACEMETHODIMP SetOutputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags ); + + IFACEMETHODIMP GetOutputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value ); + + IFACEMETHODIMP GetInputStreamPreferredState( + _In_ DWORD dwStreamID, + _Inout_ DeviceStreamState *value, + _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType ); + + IFACEMETHODIMP FlushInputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags ); + + IFACEMETHODIMP FlushOutputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags ); + + IFACEMETHODIMP_(VOID) FlushAllStreams( + VOID + ); + + // + //IKSControl Inferface function declarations + // + IFACEMETHODIMP KsEvent( + _In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + IFACEMETHODIMP KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + IFACEMETHODIMP KsMethod( + _In_reads_bytes_(ulPropertyLength) PKSMETHOD pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + + static HRESULT CreateInstance( + REFIID iid, void **ppMFT); + + __inline BOOL isPhotoModePhotoSequence() + { + return m_PhotoModeIsPhotoSequence; + } + + __inline DWORD GetQueueId() + { + return m_dwWorkQueueId; + } + + // + //Will be used from Pins to get the D3D manager once set!!! + // + __inline IFACEMETHODIMP_(VOID) GetD3DDeviceManager( + IUnknown** ppDeviceManagerUnk + ) + { + m_spDeviceManagerUnk.CopyTo( ppDeviceManagerUnk ); + } + + HRESULT SendEventToManager( + _In_ MediaEventType, + _In_ REFGUID, + _In_ UINT32 + ); + +protected: + + // + //Helper functions + // + + CInPin* GetInPin( + _In_ DWORD dwStreamID + ); + + COutPin* GetOutPin( + _In_ DWORD dwStreamID + ); + + HRESULT GetConnectedInpin(_In_ ULONG ulOutpin, _Out_ ULONG &ulInPin); + + __requires_lock_held(m_critSec) + HRESULT ChangeMediaTypeEx( + _In_ ULONG pinId, + _In_opt_ IMFMediaType *pMediaType, + _In_ DeviceStreamState newState + ); + HRESULT BridgeInputPinOutputPin( + _In_ CInPin* pInPin, + _In_ COutPin* pOutPin); + // + //Inline functions + // + + __inline IMFDeviceTransform* Parent() + { + return m_spSourceTransform.Get(); + } + + __inline VOID SetStreamingState(DeviceStreamState state) + { + InterlockedExchange((LONG*)&m_StreamingState, state); + } + + __inline DeviceStreamState GetStreamingState() + { + return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_StreamingState, 0L, 0L); + } + + __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_PhotoModeIsPhotoSequence; // used to store if the filter is in photo sequence 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<IMFDeviceTransform> m_spSourceTransform; // The sources transform. This is the pipeline DevProxy + MFSHUTDOWN_STATUS m_eShutdownStatus; + DWORD m_dwWorkQueueId; + LONG m_lWorkQueuePriority; + UINT32 m_punValue; + ComPtr<IKsControl> m_spIkscontrol; + ComPtr<IMFAttributes> m_spAttributes; + map<int, int> m_outputPinMap; // How output pins are connected to input pins i-><0..outpins> + PWCHAR m_SymbolicLink; +}; + + + +inline HRESULT MFT_CreateInstance(REFIID riid, void **ppv) +{ + return CMultipinMft::CreateInstance(riid, ppv); +} + + diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj new file mode 100644 index 00000000..3f6180f2 --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj @@ -0,0 +1,250 @@ +<?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|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</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> + <ProjectName>AvsCameraDMFT</ProjectName> + <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion> + </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 Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration"> + <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 Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets"> + <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> + <WppScanConfigurationData>common.h</WppScanConfigurationData> + </ClCompile> + <ClCompile Include="AvsCameraDMFT.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> + <WppScanConfigurationData>common.h</WppScanConfigurationData> + </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> + <WppScanConfigurationData>common.h</WppScanConfigurationData> + </ClCompile> + <ClCompile Include="AvsCameraDMFTutils.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> + <WppScanConfigurationData>common.h</WppScanConfigurationData> + </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> + <WppScanConfigurationData>common.h</WppScanConfigurationData> + </ClCompile> + </ItemGroup> + <PropertyGroup> + <TargetName>AvsCameraDMFT</TargetName> + <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\wil\include</IncludePath> + </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|ARM64'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <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> + <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories> + </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> + <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories> + </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|ARM64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories> + </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|ARM64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories> + </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 Include="Source.def" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="basepin.h" /> + <ClInclude Include="common.h" /> + <ClInclude Include="mftpeventgenerator.h" /> + <ClInclude Include="AvsCameraDMFT.h" /> + <ClInclude Include="stdafx.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters new file mode 100644 index 00000000..c3679c84 --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters @@ -0,0 +1,57 @@ +<?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="dllmain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mftpeventgenerator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="AvsCameraDMFT.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="AvsCameraDMFTutils.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> + <ItemGroup> + <ClInclude Include="basepin.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="common.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mftpeventgenerator.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="AvsCameraDMFT.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="stdafx.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp b/avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp new file mode 100644 index 00000000..4a4c75fc --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp @@ -0,0 +1,805 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" + +#pragma comment(lib, "d2d1") +#ifdef MF_WPP +#include "AvsCameraDMFTutils.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: + 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; +} + + +#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 (std::nothrow) char[len]; \ +if (!a){\ +goto done;}\ + a[0] = 0; \ + strcat_s(a, len, tStore); \ + delete(tStore); }\ +} + +// +// Queue implementation +// +CPinQueue::CPinQueue(_In_ DWORD dwPinId, _In_ IMFDeviceTransform* pParent) : + m_dwInPinId(dwPinId), m_pTransform(pParent), m_cRef(1) + +/* +Description +dwPinId is the input pin Id to which this queue corresponds +*/ +{ + m_streamCategory = GUID_NULL; +} +CPinQueue::~CPinQueue() +{ +} + +/*++ +Description: + Insert sample into the list once we reach the open queue +--*/ +STDMETHODIMP CPinQueue::Insert(_In_ IMFSample* pSample) +{ + HRESULT hr = ExceptionBoundary([&]() { + m_sampleList.push_back(pSample); + }); + + if (SUCCEEDED(hr) && m_pTransform) + { + hr = reinterpret_cast<CMultipinMft*>(m_pTransform)->QueueEvent(METransformHaveOutput, GUID_NULL, S_OK, NULL); + } + + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + // There is a bug in the pipeline that doesn't release the sample fed from processinput. We have to explicitly release the sample here + SAFE_RELEASE(pSample); + } + return hr; +} + + +/*++ +Description: + This extracts the first sample from the queue. called from Pin's ProcessOutput +--*/ + +STDMETHODIMP 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().Detach(); + } + + DMFTCHECKNULL_GOTO(*ppSample, done, MF_E_TRANSFORM_NEED_MORE_INPUT); + m_sampleList.erase(m_sampleList.begin()); +done: + return hr; +} + +/*++ +Description: + Empties the Queue. used by the flush +--*/ +VOID CPinQueue::Clear() +{ + while (!Empty()) + { + ComPtr<IMFSample> spSample; + Remove(spSample.GetAddressOf()); + } +} + +// Handle Metadata + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) +///////////////////////////////////////////////////////////////////// +// +// Handle the Metadata with the buffer +// + +HRESULT ParseMetadata_FaceDetection( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +); + +HRESULT ParseMetadata_PreviewAggregation( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +); + +HRESULT ParseMetadata_ImageAggregation( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +); + +HRESULT ParseMetadata_Histogram( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +); + +HRESULT ProcessMetadata(_In_ IMFSample* pSample) +{ + ComPtr<IMFAttributes> spMetadata; + ComPtr<IMFSample> spSample = pSample; + HRESULT hr = spSample->GetUnknown(MFSampleExtension_CaptureMetadata, IID_PPV_ARGS(spMetadata.ReleaseAndGetAddressOf())); + if (FAILED(hr)) + { + return hr; + } + + ComPtr<IMFMediaBuffer> spBuffer; + hr = spMetadata->GetUnknown(MF_CAPTURE_METADATA_FRAME_RAWSTREAM, IID_PPV_ARGS(spBuffer.ReleaseAndGetAddressOf())); + if (FAILED(hr)) + { + return hr; + } + + MediaBufferLock bufferLock(spBuffer.Get()); + BYTE* pData = NULL; + DWORD dwLength = 0; + hr = bufferLock.LockBuffer(&pData, NULL, &dwLength); + if (FAILED(hr)) + { + return hr; + } + + // OEM put meta data passing logic here, + if (FAILED(hr)) + { + return hr; + } + + LONG lBufferLeft = static_cast<LONG>(dwLength); + if (lBufferLeft < sizeof(KSCAMERA_METADATA_ITEMHEADER)) + { + return E_UNEXPECTED; + } + + PKSCAMERA_METADATA_ITEMHEADER pItem = (PKSCAMERA_METADATA_ITEMHEADER)pData; + + while (lBufferLeft > 0) + { + switch (pItem->MetadataId) + { + case MetadataId_Custom_PreviewAggregation: + hr = ParseMetadata_PreviewAggregation(pItem, spMetadata.Get()); + if (FAILED(hr)) + { + return hr; + } + break; + case MetadataId_Custom_ImageAggregation: + hr = ParseMetadata_ImageAggregation(pItem, spMetadata.Get()); + if (FAILED(hr)) + { + return hr; + } + break; + case MetadataId_Custom_Histogram: + hr = ParseMetadata_Histogram(pItem, spMetadata.Get()); + if (FAILED(hr)) + { + return hr; + } + break; + case MetadataId_Custom_FaceDetection: + hr = ParseMetadata_FaceDetection(pItem, spMetadata.Get()); + if (FAILED(hr)) + { + return hr; + } + } + + if (!pItem->Size) + { + // 0 size item will cause the loop to break and + // we will report buffer malformated + break; + } + lBufferLeft -= (LONG)pItem->Size; + if (lBufferLeft < sizeof(KSCAMERA_METADATA_ITEMHEADER)) + { + break; + } + pItem = reinterpret_cast<PKSCAMERA_METADATA_ITEMHEADER> + (reinterpret_cast<PBYTE>(pItem) + pItem->Size); + } + + if (lBufferLeft != 0) + { + //Check and log for malformated data + return E_UNEXPECTED; + } + + return S_OK; +} + +HRESULT ParseMetadata_PreviewAggregation( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +) +{ + HRESULT hr = S_OK; + if (pItem->Size < sizeof(CAMERA_METADATA_PREVIEWAGGREGATION)) + { + return E_UNEXPECTED; + } + + PCAMERA_METADATA_PREVIEWAGGREGATION pFixedStruct = + (PCAMERA_METADATA_PREVIEWAGGREGATION)pItem; + + if (pFixedStruct->Data.FocusState.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_FOCUSSTATE, + pFixedStruct->Data.FocusState.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.ExposureTime.Set) + { + hr = pMetaDataAttributes->SetUINT64( + MF_CAPTURE_METADATA_EXPOSURE_TIME, + pFixedStruct->Data.ExposureTime.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.ISOSpeed.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_ISO_SPEED, + pFixedStruct->Data.ISOSpeed.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.LensPosition.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_LENS_POSITION, + pFixedStruct->Data.LensPosition.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.FlashOn.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_FLASH, + pFixedStruct->Data.FlashOn.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.WhiteBalanceMode.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_WHITEBALANCE, + pFixedStruct->Data.WhiteBalanceMode.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.EVCompensation.Set) + { + CapturedMetadataExposureCompensation EVCompensation; + + EVCompensation.Flags = pFixedStruct->Data.EVCompensation.Flags; + EVCompensation.Value = pFixedStruct->Data.EVCompensation.Value; + + hr = pMetaDataAttributes->SetBlob( + MF_CAPTURE_METADATA_EXPOSURE_COMPENSATION, + (const UINT8*)&EVCompensation, + sizeof(EVCompensation)); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.SensorFrameRate.Set) + { + hr = pMetaDataAttributes->SetUINT64( + MF_CAPTURE_METADATA_SENSORFRAMERATE, + pFixedStruct->Data.SensorFrameRate.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.IsoAnalogGain.Set || + pFixedStruct->Data.IsoDigitalGain.Set) + { + CapturedMetadataISOGains IsoGains; + + if (pFixedStruct->Data.IsoAnalogGain.Set) + { + IsoGains.AnalogGain = + FLOAT(pFixedStruct->Data.IsoAnalogGain.Numerator) / + FLOAT(pFixedStruct->Data.IsoAnalogGain.Denominator); + } + if (pFixedStruct->Data.IsoDigitalGain.Set) + { + IsoGains.DigitalGain = + FLOAT(pFixedStruct->Data.IsoDigitalGain.Numerator) / + FLOAT(pFixedStruct->Data.IsoDigitalGain.Denominator); + } + + hr = pMetaDataAttributes->SetBlob( + MF_CAPTURE_METADATA_ISO_GAINS, + (const UINT8*)&IsoGains, + sizeof(IsoGains)); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.WhiteBalanceGain_R.Set || + pFixedStruct->Data.WhiteBalanceGain_G.Set || + pFixedStruct->Data.WhiteBalanceGain_B.Set) + { + CapturedMetadataWhiteBalanceGains WhiteBalanceGains; + + if (pFixedStruct->Data.WhiteBalanceGain_R.Set) + { + WhiteBalanceGains.R = + FLOAT(pFixedStruct->Data.WhiteBalanceGain_R.Numerator) / + FLOAT(pFixedStruct->Data.WhiteBalanceGain_R.Denominator); + } + if (pFixedStruct->Data.WhiteBalanceGain_G.Set) + { + WhiteBalanceGains.G = + FLOAT(pFixedStruct->Data.WhiteBalanceGain_G.Numerator) / + FLOAT(pFixedStruct->Data.WhiteBalanceGain_G.Denominator); + } + if (pFixedStruct->Data.WhiteBalanceGain_B.Set) + { + WhiteBalanceGains.B = + FLOAT(pFixedStruct->Data.WhiteBalanceGain_B.Numerator) / + FLOAT(pFixedStruct->Data.WhiteBalanceGain_B.Denominator); + } + + hr = pMetaDataAttributes->SetBlob( + MF_CAPTURE_METADATA_WHITEBALANCE_GAINS, + (const UINT8*)&WhiteBalanceGains, + sizeof(WhiteBalanceGains)); + if (FAILED(hr)) + { + return hr; + } + } + + return S_OK; +} + +HRESULT ParseMetadata_ImageAggregation( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +) +{ + HRESULT hr = S_OK; + if (pItem->Size < sizeof(CAMERA_METADATA_IMAGEAGGREGATION)) + { + return E_UNEXPECTED; + } + + PCAMERA_METADATA_IMAGEAGGREGATION pFixedStruct = + (PCAMERA_METADATA_IMAGEAGGREGATION)pItem; + + if (pFixedStruct->Data.FrameId.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_REQUESTED_FRAME_SETTING_ID, + pFixedStruct->Data.FrameId.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.ExposureTime.Set) + { + hr = pMetaDataAttributes->SetUINT64( + MF_CAPTURE_METADATA_EXPOSURE_TIME, + pFixedStruct->Data.ExposureTime.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.ISOSpeed.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_ISO_SPEED, + pFixedStruct->Data.ISOSpeed.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.LensPosition.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_LENS_POSITION, + pFixedStruct->Data.LensPosition.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.SceneMode.Set) + { + hr = pMetaDataAttributes->SetUINT64( + MF_CAPTURE_METADATA_SCENE_MODE, + pFixedStruct->Data.SceneMode.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.FlashOn.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_FLASH, + pFixedStruct->Data.FlashOn.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.FlashPower.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_FLASH_POWER, + pFixedStruct->Data.FlashPower.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.WhiteBalanceMode.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_WHITEBALANCE, + pFixedStruct->Data.WhiteBalanceMode.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.ZoomFactor.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_ZOOMFACTOR, + pFixedStruct->Data.ZoomFactor.Value); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.EVCompensation.Set) + { + CapturedMetadataExposureCompensation EVCompensation; + + EVCompensation.Flags = pFixedStruct->Data.EVCompensation.Flags; + EVCompensation.Value = pFixedStruct->Data.EVCompensation.Value; + + hr = pMetaDataAttributes->SetBlob( + MF_CAPTURE_METADATA_EXPOSURE_COMPENSATION, + (const UINT8*)&EVCompensation, + sizeof(EVCompensation)); + if (FAILED(hr)) + { + return hr; + } + } + + if (pFixedStruct->Data.FocusState.Set) + { + hr = pMetaDataAttributes->SetUINT32( + MF_CAPTURE_METADATA_FOCUSSTATE, + pFixedStruct->Data.FocusState.Value); + if (FAILED(hr)) + { + return hr; + } + } + return S_OK; +} +#endif // (NTDDI_VERSION >= NTDDI_WINBLUE) +struct HistogramData +{ + HistogramDataHeader Header; + ULONG Color[256]; + + HistogramData() + { + Header.Size = sizeof(*this); + Header.ChannelMask = 0; + Header.Linear = 1; + RtlZeroMemory(Color, sizeof(Color)); + } +}; + +// This is the blob we pass back every time. +template <ULONG I> +struct Histogram +{ + HistogramBlobHeader Blob; + // RGB or YUV Histograms. + HistogramHeader Header; + HistogramData Data[I]; + + Histogram( + _In_ ULONG Width = 0, + _In_ ULONG Height = 0 + ) + { + Blob.Histograms = 1; + Blob.Size = sizeof(*this); + + Header.Size = sizeof(Header) + sizeof(Data); + Header.Bins = 256; + Header.Grid.Height = Height; + Header.Grid.Width = Width; + Header.Grid.Region.top = 0; + Header.Grid.Region.left = 0; + Header.Grid.Region.bottom = Height - 1; + Header.Grid.Region.right = Width - 1; + } +}; + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) +#define MF_HISTOGRAM_RGB (MF_HISTOGRAM_CHANNEL_R | MF_HISTOGRAM_CHANNEL_G | MF_HISTOGRAM_CHANNEL_B ) +#define MF_HISTOGRAM_YCrCb (MF_HISTOGRAM_CHANNEL_Y | MF_HISTOGRAM_CHANNEL_Cr | MF_HISTOGRAM_CHANNEL_Cb) + +HRESULT ParseMetadata_Histogram( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +) +{ + if (pItem->Size < sizeof(CAMERA_METADATA_HISTOGRAM)) + { + return E_UNEXPECTED; + } + + PCAMERA_METADATA_HISTOGRAM pHistogram = (PCAMERA_METADATA_HISTOGRAM)pItem; + + if ((pHistogram->Data.ChannelMask & MF_HISTOGRAM_RGB) == MF_HISTOGRAM_RGB) + { + Histogram<4> Blob(pHistogram->Data.Width, pHistogram->Data.Height); + + Blob.Header.FourCC = pHistogram->Data.FourCC; + Blob.Header.ChannelMasks = pHistogram->Data.ChannelMask; + + // For a RGB Histogram, we fake the Y channel by copying the G channel. + Blob.Data[0].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Y; + RtlCopyMemory(Blob.Data[0].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[0].Color)); + + // Now just copy the RGB channels normally. + Blob.Data[1].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_R; + RtlCopyMemory(Blob.Data[1].Color, pHistogram->Data.P0Data, sizeof(Blob.Data[1].Color)); + Blob.Data[2].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_G; + RtlCopyMemory(Blob.Data[2].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[2].Color)); + Blob.Data[3].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_B; + RtlCopyMemory(Blob.Data[3].Color, pHistogram->Data.P2Data, sizeof(Blob.Data[3].Color)); + + return pMetaDataAttributes->SetBlob( + MF_CAPTURE_METADATA_HISTOGRAM, + (PBYTE)&Blob, + sizeof(Blob) + ); + } + else if ((pHistogram->Data.ChannelMask & MF_HISTOGRAM_YCrCb) == MF_HISTOGRAM_YCrCb) + { + Histogram<3> Blob(pHistogram->Data.Width, pHistogram->Data.Height); + + Blob.Header.FourCC = pHistogram->Data.FourCC; + Blob.Header.ChannelMasks = pHistogram->Data.ChannelMask; + + Blob.Data[0].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Y; + RtlCopyMemory(Blob.Data[0].Color, pHistogram->Data.P0Data, sizeof(Blob.Data[0].Color)); + Blob.Data[1].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Cr; + RtlCopyMemory(Blob.Data[1].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[1].Color)); + Blob.Data[2].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Cb; + RtlCopyMemory(Blob.Data[2].Color, pHistogram->Data.P2Data, sizeof(Blob.Data[2].Color)); + + //TODO: + return pMetaDataAttributes->SetBlob( + MF_CAPTURE_METADATA_HISTOGRAM, + (PBYTE)&Blob, + sizeof(Blob) + ); + } + return E_UNEXPECTED; +} + +HRESULT ParseMetadata_FaceDetection( + _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, + _In_ IMFAttributes* pMetaDataAttributes +) +{ + HRESULT hr = S_OK; + + if (pItem->Size < sizeof(CAMERA_METADATA_FACEHEADER)) + { + return E_UNEXPECTED; + } + + PCAMERA_METADATA_FACEHEADER pFaceHeader = (PCAMERA_METADATA_FACEHEADER)pItem; + + if (pItem->Size < (sizeof(CAMERA_METADATA_FACEHEADER) + (sizeof(METADATA_FACEDATA) * pFaceHeader->Count))) + { + return E_UNEXPECTED; + } + PMETADATA_FACEDATA pFaceData = (PMETADATA_FACEDATA)(pFaceHeader + 1); + UINT32 cbRectSize = sizeof(FaceRectInfoBlobHeader) + (sizeof(FaceRectInfo) * (pFaceHeader->Count)); + BYTE* pRectBuf = new (std::nothrow) BYTE[cbRectSize]; + if (pRectBuf == NULL) + { + return E_OUTOFMEMORY; + } + + UINT32 cbCharSize = sizeof(FaceCharacterizationBlobHeader) + (sizeof(FaceCharacterization) * (pFaceHeader->Count)); + BYTE* pCharBuf = new (std::nothrow) BYTE[cbCharSize]; + if (pCharBuf == NULL) + { + delete[] pRectBuf; + return E_OUTOFMEMORY; + } + + FaceRectInfoBlobHeader* pFaceRectHeader = (FaceRectInfoBlobHeader*)pRectBuf; + pFaceRectHeader->Size = cbRectSize; + pFaceRectHeader->Count = pFaceHeader->Count; + + FaceCharacterizationBlobHeader* pFaceCharHeader = (FaceCharacterizationBlobHeader*)pCharBuf; + pFaceCharHeader->Size = cbCharSize; + pFaceCharHeader->Count = pFaceHeader->Count; + + FaceRectInfo* FaceRegions = (FaceRectInfo*)(pFaceRectHeader + 1); + FaceCharacterization* FaceChars = (FaceCharacterization*)(pFaceCharHeader + 1); + + for (UINT i = 0; i < pFaceHeader->Count; i++) + { + FaceRegions[i].Region = pFaceData[i].Region; + FaceRegions[i].confidenceLevel = pFaceData[i].confidenceLevel; + + FaceChars[i].BlinkScoreLeft = pFaceData[i].BlinkScoreLeft; + FaceChars[i].BlinkScoreRight = pFaceData[i].BlinkScoreRight; + FaceChars[i].FacialExpression = (pFaceData[i].FacialExpression == EXPRESSION_SMILE) ? MF_METADATAFACIALEXPRESSION_SMILE : 0; + FaceChars[i].FacialExpressionScore = pFaceData[i].FacialExpressionScore; + } + + hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROIS, pRectBuf, cbRectSize); + if (FAILED(hr)) + { + goto done; + } + + MetadataTimeStamps timestamp; + timestamp.Flags = MF_METADATATIMESTAMPS_DEVICE; + timestamp.Device = pFaceHeader->Timestamp; + + hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROITIMESTAMPS, (const UINT8*)×tamp, sizeof(MetadataTimeStamps)); + if (FAILED(hr)) + { + goto done; + } + +#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) + // Include characterization data if any of the associated bits were set. + if (pFaceHeader->Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_ADVANCED_MASK) + { + hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROICHARACTERIZATIONS, pCharBuf, cbCharSize); + } +#endif // (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) + +done: + delete[] pRectBuf; + delete[] pCharBuf; + + return hr; +} +#endif diff --git a/avstream/avscamera/DMFT/Source.def b/avstream/avscamera/DMFT/Source.def new file mode 100644 index 00000000..752ef2ea --- /dev/null +++ b/avstream/avscamera/DMFT/Source.def @@ -0,0 +1,5 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DllGetClassObject PRIVATE diff --git a/avstream/avscamera/DMFT/basepin.cpp b/avstream/avscamera/DMFT/basepin.cpp new file mode 100644 index 00000000..e0178390 --- /dev/null +++ b/avstream/avscamera/DMFT/basepin.cpp @@ -0,0 +1,625 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "stdafx.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) + , m_nRefCount(0) + , m_state(DeviceStreamState_Stop) + , m_dwWorkQueueId(MFASYNC_CALLBACK_QUEUE_UNDEFINED) +{ + +} + +CBasePin::~CBasePin() +{ + m_listOfMediaTypes.clear(); + m_spAttributes = nullptr; +} + +IFACEMETHODIMP_(DeviceStreamState) CBasePin::GetState() +{ + return (DeviceStreamState) InterlockedCompareExchange((PLONG)&m_state, 0L,0L); +} + +IFACEMETHODIMP_(DeviceStreamState) CBasePin::SetState(_In_ DeviceStreamState state) +{ + return (DeviceStreamState) InterlockedExchange((LONG*)&m_state, state); +} + +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); + 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()); + ComPtr<IMFMediaType> spMediaType; + DMFTCHECKNULL_GOTO(ppMediaType,done,E_INVALIDARG); + *ppMediaType = nullptr; + if (pos >= m_listOfMediaTypes.size()) + { + DMFTCHECKHR_GOTO(MF_E_NO_MORE_TYPES,done); + } + spMediaType = m_listOfMediaTypes[pos]; + *ppMediaType = spMediaType.Detach(); +done: + return hr; +} + +IFACEMETHODIMP_(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) { + DMFTCHECKHR_GOTO(m_listOfMediaTypes[uIIndex].CopyTo(ppIMFMediaTypeFull), done); + } + break; + } + else if (FAILED(hr)) + { + DMFTCHECKHR_GOTO(hr,done); + } + } +done: + return SUCCEEDED(hr) ? TRUE : FALSE; +} + +IFACEMETHODIMP 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, done, E_POINTER); + *ppv = nullptr; + if ( iid == __uuidof( IUnknown ) ) + { + *ppv = static_cast<VOID*>(this); + } + else if ( iid == __uuidof( IMFAttributes ) ) + { + *ppv = static_cast< IMFAttributes* >( this ); + } + else if ( iid == __uuidof( IKsControl ) ) + { + *ppv = static_cast< IKsControl* >( this ); + } + else + { + hr = E_NOINTERFACE; + goto done; + } + AddRef(); +done: + return hr; +} + +VOID CBasePin::SetD3DManager(_In_opt_ IUnknown* pManager) +{ + // + // Should release the old dxgi manager.. We will not invalidate the pins or allocators + // We will recreate all allocator when the media types are set, so we should be fine + // And the pipeline will not set the dxgimanager when the pipeline is already built + // + CAutoLock Lock(lock()); + m_spDxgiManager = pManager; + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting D3DManager on pin %d", m_StreamId); +} +// +//Input Pin implementation +// +CInPin::CInPin( + _In_opt_ IMFAttributes *pAttributes, + _In_ ULONG ulPinId, + _In_ CMultipinMft *pParent) + : + CBasePin(ulPinId, pParent), + m_stStreamType(GUID_NULL), + m_waitInputMediaTypeWaiter(NULL), + m_preferredStreamState(DeviceStreamState_Stop) +{ + setAttributes(pAttributes); +} + +CInPin::~CInPin() +{ + setAttributes( nullptr ); + m_spSourceTransform = nullptr; + + if (m_waitInputMediaTypeWaiter) + { + CloseHandle(m_waitInputMediaTypeWaiter); + } +} + +IFACEMETHODIMP CInPin::Init( + _In_ IMFDeviceTransform* 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, + nullptr + ); + 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; +} + +HRESULT 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->GetOutputAvailableType(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; +} + +IFACEMETHODIMP CInPin::SendSample( + _In_ IMFSample *pSample + ) +{ + HRESULT hr = S_OK; + CAutoLock Lock(lock()); + if (FAILED(Active())) + { + goto done; + } + COutPin *poPin = static_cast<COutPin*>(m_outpin.Get()); + DMFTCHECKNULL_GOTO(pSample, done, S_OK); + DMFTCHECKHR_GOTO(poPin->AddSample(pSample, this), done); + + done: + return hr; +} + +IFACEMETHODIMP_(VOID) CInPin::ConnectPin( _In_ CBasePin * poPin ) +{ + CAutoLock Lock(lock()); + if (poPin!=nullptr) + { + m_outpin = poPin; + } +} + +IFACEMETHODIMP CInPin::WaitForSetInputPinMediaChange() +{ + DWORD dwWait = 0; + HRESULT hr = S_OK; + + dwWait = WaitForSingleObject( m_waitInputMediaTypeWaiter, INFINITE ); + + if ( dwWait != WAIT_OBJECT_0 ) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto done; + } +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +HRESULT 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_spPrefferedMediaType != nullptr ) + { + m_spPrefferedMediaType.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_spPrefferedMediaType = nullptr; + SetEvent(m_waitInputMediaTypeWaiter); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +IFACEMETHODIMP_(VOID) CInPin::ShutdownPin() +{ + m_spSourceTransform = nullptr; + m_outpin = nullptr; +} +// +//Output Pin Implementation +// +COutPin::COutPin( + _In_ ULONG ulPinId, + _In_opt_ CMultipinMft *pparent, + _In_ IKsControl* pIksControl + ) + : CBasePin(ulPinId, pparent) + , m_firstSample(false) + , m_queue(nullptr) +{ + HRESULT hr = S_OK; + ComPtr<IMFAttributes> spAttributes; + + // + //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() +{ + m_spAttributes = nullptr; + SAFE_DELETE(m_queue); +} + +/*++ +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. +--*/ +IFACEMETHODIMP COutPin::AddPin( + _In_ DWORD inputPinId + ) +{ + // + //Add a new queue corresponding to the input pin + // + HRESULT hr = S_OK; + CAutoLock Lock(lock()); + + m_queue = new (std::nothrow) CPinQueue(inputPinId,Parent()); + DMFTCHECKNULL_GOTO(m_queue, done, E_OUTOFMEMORY ); +done: + + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return S_OK; +} +/*++ +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 +--*/ + +IFACEMETHODIMP COutPin::AddSample( + _In_ IMFSample *pSample, + _In_ CBasePin *pPin) +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(pPin); + + CAutoLock Lock(lock()); // Serialize + + DMFTCHECKNULL_GOTO(pSample, done, E_INVALIDARG); + if (FAILED(Active())) + { + goto done; + } + DMFTCHECKHR_GOTO(m_queue->Insert(pSample), done); +done: + if (FAILED(hr)) + { + // Throw an Error to the pipeline + DMFTCHECKHR_GOTO(Parent()->QueueEvent(MEError, GUID_NULL, hr, NULL), done); + } + return hr; +} + +/*++ +COutPin::SetState +Description: +State setter for the output pin +--*/ +IFACEMETHODIMP_(VOID) COutPin::SetFirstSample( + _In_ BOOL fisrtSample ) +{ + m_firstSample = fisrtSample; +} + +/*++ +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() ); + (VOID)m_queue->Clear(); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} +/*++ +COutPin::ChangeMediaTypeFromInpin +Description: +called from the Device Transform 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_ IMFMediaType* pOutMediaType, + _In_ DeviceStreamState state) +{ + HRESULT hr = S_OK; + 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); + DMFTCHECKHR_GOTO(FlushQueues(),done); + DMFTCHECKNULL_GOTO(m_queue,done, E_UNEXPECTED); // The queue should alwaye be set + if ( SUCCEEDED( hr ) ) + { + (VOID)setMediaType( pOutMediaType ); + (VOID)SetState( state ); + } +done: + return hr; +} + +/*++ +Description: + called from the IMFdeviceTransform's +--*/ + +IFACEMETHODIMP 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 Transform 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 received the transform or not. + If we have received the sample and we are passing out a sample we should reset the trigger set on the Device Transform +--*/ + +IFACEMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags, + _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample, + _Out_ DWORD *pdwStatus + ) +{ + HRESULT hr = S_OK; + ComPtr<IMFSample> spSample; + UNREFERENCED_PARAMETER(pdwStatus); + UNREFERENCED_PARAMETER(dwFlags); + CAutoLock lock(lock()); + MFTIME llTime = 0; + if (FAILED(Active())) + { + goto done; + } + DMFTCHECKNULL_GOTO(m_queue, done, MF_E_INVALID_STREAM_STATE); + pOutputSample->dwStatus = S_OK; + + DMFTCHECKHR_GOTO(m_queue->Remove(spSample.GetAddressOf()), done); + + if (FAILED(spSample->GetSampleTime(&llTime))) + { + spSample->SetSampleTime(MFGetSystemTime()); + } + if (m_firstSample) + { + spSample->SetUINT32(MFSampleExtension_Discontinuity,TRUE); + SetFirstSample(FALSE); + } + // + // Any processing before we pass the sample to further in the pipeline should be done here + // PROCESSSAMPLE(pSample); There is a bug in the pipeline and to circumvent that we have to + // keep a reference on the sample. The pipeline is not releasing a reference when the sample + // is fed in ProcessInput. We are explicitly releasing it for the pipeline. + // + pOutputSample->pSample = spSample.Detach(); + pOutputSample->dwStatus = S_OK; +done: + return hr; +} + +/*++ + COutPin::KsProperty +Description: +The KsProperty for the Pin.. this is to reroute all pin kscontrols to the input pin +--*/ +IFACEMETHODIMP 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/avscamera/DMFT/basepin.h b/avstream/avscamera/DMFT/basepin.h new file mode 100644 index 00000000..8051188a --- /dev/null +++ b/avstream/avscamera/DMFT/basepin.h @@ -0,0 +1,568 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once +#include "stdafx.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 IFACEMETHODIMP_(DeviceStreamState) GetState(); + virtual IFACEMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState State); + + + // + //IUnknown Interface functions + // + + IFACEMETHODIMP_(ULONG) AddRef( + void + ) + { + return InterlockedIncrement(&m_nRefCount); + } + IFACEMETHODIMP_(ULONG) Release( + void + ) + { + ULONG uCount = InterlockedDecrement(&m_nRefCount); + if (uCount == 0) + { + delete this; + } + return uCount; + } + + IFACEMETHODIMP_(HRESULT) QueryInterface( + _In_ REFIID riid, + _Outptr_result_maybenull_ void **ppvObject + ); + // + // IKsControl Interface functions + // + + IFACEMETHODIMP 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; + } + } + virtual IFACEMETHODIMP FlushQueues( + ) + { + return S_OK; + } + // + // NOOPs for this iteration.. + // + IFACEMETHODIMP 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; + } + + IFACEMETHODIMP 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 + // + IFACEMETHODIMP GetItem( + _In_ REFGUID guidKey, + _Inout_opt_ PROPVARIANT* pValue + ) + { + return m_spAttributes->GetItem(guidKey, pValue); + } + + IFACEMETHODIMP GetItemType( + _In_ REFGUID guidKey, + _Out_ MF_ATTRIBUTE_TYPE* pType + ) + { + return m_spAttributes->GetItemType(guidKey, pType); + } + + IFACEMETHODIMP CompareItem( + _In_ REFGUID guidKey, + _In_ REFPROPVARIANT Value, + _Out_ BOOL* pbResult + ) + { + return m_spAttributes->CompareItem(guidKey, Value, pbResult); + } + + IFACEMETHODIMP Compare( + _In_ IMFAttributes* pTheirs, + _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType, + _Out_ BOOL* pbResult + ) + { + return m_spAttributes->Compare(pTheirs, MatchType, pbResult); + } + + IFACEMETHODIMP GetUINT32( + _In_ REFGUID guidKey, + _Out_ UINT32* punValue + ) + { + return m_spAttributes->GetUINT32(guidKey, punValue); + } + + IFACEMETHODIMP GetUINT64( + _In_ REFGUID guidKey, + _Out_ UINT64* punValue + ) + { + return m_spAttributes->GetUINT64(guidKey, punValue); + } + + IFACEMETHODIMP GetDouble( + _In_ REFGUID guidKey, + _Out_ double* pfValue + ) + { + return m_spAttributes->GetDouble(guidKey, pfValue); + } + + IFACEMETHODIMP GetGUID( + _In_ REFGUID guidKey, + _Out_ GUID* pguidValue + ) + { + return m_spAttributes->GetGUID(guidKey, pguidValue); + } + + IFACEMETHODIMP GetStringLength( + _In_ REFGUID guidKey, + _Out_ UINT32* pcchLength + ) + { + return m_spAttributes->GetStringLength(guidKey, pcchLength); + } + + IFACEMETHODIMP GetString( + _In_ REFGUID guidKey, + _Out_writes_(cchBufSize) LPWSTR pwszValue, + _In_ UINT32 cchBufSize, + _Inout_opt_ UINT32* pcchLength + ) + { + return m_spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength); + } + + IFACEMETHODIMP GetAllocatedString( + _In_ REFGUID guidKey, + _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue, + _Inout_ UINT32* pcchLength + ) + { + return m_spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength); + } + + IFACEMETHODIMP GetBlobSize( + _In_ REFGUID guidKey, + _Out_ UINT32* pcbBlobSize + ) + { + return m_spAttributes->GetBlobSize(guidKey, pcbBlobSize); + } + + IFACEMETHODIMP GetBlob( + _In_ REFGUID guidKey, + _Out_writes_(cbBufSize) UINT8* pBuf, + UINT32 cbBufSize, + _Inout_ UINT32* pcbBlobSize + ) + { + return m_spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize); + } + + IFACEMETHODIMP 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); + } + + IFACEMETHODIMP GetUnknown( + __RPC__in REFGUID guidKey, + __RPC__in REFIID riid, + __RPC__deref_out_opt LPVOID *ppv + ) + { + return m_spAttributes->GetUnknown(guidKey, riid, ppv); + } + + IFACEMETHODIMP SetItem( + _In_ REFGUID guidKey, + _In_ REFPROPVARIANT Value + ) + { + return m_spAttributes->SetItem(guidKey, Value); + } + + IFACEMETHODIMP DeleteItem( + _In_ REFGUID guidKey + ) + { + return m_spAttributes->DeleteItem(guidKey); + } + + IFACEMETHODIMP DeleteAllItems() + { + return m_spAttributes->DeleteAllItems(); + } + + IFACEMETHODIMP SetUINT32( + _In_ REFGUID guidKey, + _In_ UINT32 unValue + ) + { + return m_spAttributes->SetUINT32(guidKey, unValue); + } + + IFACEMETHODIMP SetUINT64( + _In_ REFGUID guidKey, + _In_ UINT64 unValue + ) + { + return m_spAttributes->SetUINT64(guidKey, unValue); + } + + IFACEMETHODIMP SetDouble( + _In_ REFGUID guidKey, + _In_ double fValue + ) + { + return m_spAttributes->SetDouble(guidKey, fValue); + } + + IFACEMETHODIMP SetGUID( + _In_ REFGUID guidKey, + _In_ REFGUID guidValue + ) + { + return m_spAttributes->SetGUID(guidKey, guidValue); + } + + IFACEMETHODIMP SetString( + _In_ REFGUID guidKey, + _In_ LPCWSTR wszValue + ) + { + return m_spAttributes->SetString(guidKey, wszValue); + } + + IFACEMETHODIMP SetBlob( + _In_ REFGUID guidKey, + _In_reads_(cbBufSize) const UINT8* pBuf, + UINT32 cbBufSize + ) + { + return m_spAttributes->SetBlob(guidKey, pBuf, cbBufSize); + } + + IFACEMETHODIMP SetUnknown( + _In_ REFGUID guidKey, + _In_ IUnknown* pUnknown + ) + { + return m_spAttributes->SetUnknown(guidKey, pUnknown); + } + + IFACEMETHODIMP LockStore() + { + return m_spAttributes->LockStore(); + } + + IFACEMETHODIMP UnlockStore() + { + return m_spAttributes->UnlockStore(); + } + + IFACEMETHODIMP GetCount( + _Out_ UINT32* pcItems + ) + { + return m_spAttributes->GetCount(pcItems); + } + + IFACEMETHODIMP GetItemByIndex( + UINT32 unIndex, + _Out_ GUID* pguidKey, + _Inout_ PROPVARIANT* pValue + ) + { + return m_spAttributes->GetItemByIndex(unIndex, pguidKey, pValue); + } + + IFACEMETHODIMP CopyAllItems( + _In_ IMFAttributes* pDest + ) + { + return m_spAttributes->CopyAllItems(pDest); + } + + // + //Helper Functions + // + __requires_lock_held(m_lock) + __inline HRESULT Active() + { + return (m_state == DeviceStreamState_Run)?S_OK:HRESULT_FROM_WIN32(ERROR_INVALID_STATE); + } + __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 IFACEMETHODIMP getPinAttributes (_In_ IMFAttributes **ppAttributes) + { + return QueryInterface( IID_PPV_ARGS(ppAttributes) ); + } + + IFACEMETHODIMP AddMediaType( + _Inout_ DWORD *pos, + _In_ IMFMediaType *pMediatype); /*Filling the media types data structure*/ + IFACEMETHODIMP GetMediaTypeAt( + _In_ DWORD pos, + _Outptr_result_maybenull_ IMFMediaType **pMediaType); /* getting the data from the data structure*/ + IFACEMETHODIMP_(BOOL) IsMediaTypeSupported( + _In_ IMFMediaType *pMediaType, + _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_) + IMFMediaType **ppIMFMediaTypeFull); + IFACEMETHODIMP GetOutputAvailableType( + _In_ DWORD dwTypeIndex, + _Out_opt_ IMFMediaType **ppType); + + VOID SetD3DManager(_In_opt_ IUnknown* pManager); + VOID SetWorkQueue(_In_ DWORD dwQueueId) + { + m_dwWorkQueueId = dwQueueId; + } +protected: + // + //Inline helper functions + // + _inline CMultipinMft* Parent() + { + return m_Parent; + } + __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; + DeviceStreamState m_state; + ComPtr<IUnknown> m_spDxgiManager; + DWORD m_dwWorkQueueId; +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; + CMultipinMft* m_Parent; + ULONG m_nRefCount; +}; + + + +class CInPin: public CBasePin{ +public: + CInPin( _In_opt_ IMFAttributes*, _In_ ULONG ulPinId = 0, _In_ CMultipinMft *pParent=NULL); + ~CInPin(); + + IFACEMETHODIMP Init( + _In_ IMFDeviceTransform * + ); + IFACEMETHODIMP_(VOID) ConnectPin( + _In_ CBasePin * + ); + IFACEMETHODIMP SendSample( + _In_ IMFSample * + ); + HRESULT GenerateMFMediaTypeListFromDevice( + _In_ UINT uiStreamId + ); + IFACEMETHODIMP WaitForSetInputPinMediaChange( + ); + // + //Corresponding IMFDeviceTransform functions for the Pin + // + HRESULT GetInputStreamPreferredState( + _Inout_ DeviceStreamState *value, + _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType + ); + HRESULT SetInputStreamState( + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags + ); + + virtual IFACEMETHODIMP FlushQueues() + { + return S_OK; + } + // + //Inline functions + // + __inline IMFMediaType* getPreferredMediaType() + { + return m_spPrefferedMediaType.Get(); + } + __inline VOID setPreferredMediaType( _In_ IMFMediaType *pMediaType) + { + m_spPrefferedMediaType = pMediaType; + } + __inline DeviceStreamState setPreferredStreamState(_In_ DeviceStreamState streamState) + { + return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_preferredStreamState, (LONG)streamState, (LONG)m_preferredStreamState); + } + __inline DeviceStreamState getPreferredStreamState() + { + return m_preferredStreamState; + } + + IFACEMETHODIMP_( VOID) ShutdownPin(); + +protected: + ComPtr<IMFDeviceTransform> m_spSourceTransform; /*Source Transform i.e. DevProxy*/ + GUID m_stStreamType; /*GUID representing the GUID*/ + ComPtr<CBasePin> m_outpin; //Only one output pin connected per input pin. There can be multiple pins connected and this could be a list + DeviceStreamState m_preferredStreamState; + ComPtr<IMFMediaType> m_spPrefferedMediaType; + 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(); + IFACEMETHODIMP FlushQueues(); + IFACEMETHODIMP AddPin( + _In_ DWORD pinId + ); + virtual IFACEMETHODIMP AddSample( + _In_ IMFSample *pSample, + _In_ CBasePin *inPin + ); + IFACEMETHODIMP GetOutputStreamInfo( + _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo + ); + virtual IFACEMETHODIMP ChangeMediaTypeFromInpin( + _In_ IMFMediaType* pOutMediaType, + _In_ DeviceStreamState state ); + IFACEMETHODIMP ProcessOutput ( + _In_ DWORD dwFlags, + _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample, + _Out_ DWORD *pdwStatus + ); + IFACEMETHODIMP KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned + ); + IFACEMETHODIMP_(VOID) SetFirstSample( + _In_ BOOL + ); + + UINT32 GetMediatypeCount() + { + return (UINT32)m_listOfMediaTypes.size(); + } + +protected: + CPinQueue * m_queue; /* Queue where the sample will be stored*/ + BOOL m_firstSample; +}; + diff --git a/avstream/avscamera/DMFT/common.h b/avstream/avscamera/DMFT/common.h new file mode 100644 index 00000000..b6e636a8 --- /dev/null +++ b/avstream/avscamera/DMFT/common.h @@ -0,0 +1,360 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#pragma once + +#ifndef MF_WPP +#define DMFTRACE(...) +#endif + +// +// 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 +// {836E84ED-45E9-4160-A79D-771F1C718CD2} for the Pipeline to pick up the Transform. +// + +DEFINE_GUID(CLSID_AvsCameraDMFT, 0x836e84ed, 0x45e9, 0x4160, 0xa7, 0x9d, 0x77, 0x1f, 0x1c, 0x71, 0x8c, 0xd2); + +#ifdef DBG +#define mf_assert(a) if(!a) DebugBreak() +#else +#define mf_assert(a) +#endif + +#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 WPP_CHECK_LEVEL_ENABLED(flags, level) 1 + +//begin_wpp config +// +// USEPREFIX (DMFTCHECKNULL_GOTO,"%!STDPREFIX!"); +// FUNC DMFTCHECKNULL_GOTO(CHECKNULLGOTO_EXP,LABEL,HR,...); +// USESUFFIX (DMFTCHECKNULL_GOTO," failed %!HRESULT!\n", hr); +// +//end_wpp + +//begin_wpp config +// +// USEPREFIX (DMFTCHECKHR_GOTO,"%!STDPREFIX!"); +// FUNC DMFTCHECKHR_GOTO(CHECKHRGOTO_EXP,LABEL,...); +// USESUFFIX (DMFTCHECKHR_GOTO," failed %!HRESULT!\n", hr); +// + +//end_wpp + +#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_PRE(pointer,label,HR) if( pointer == NULL ) { hr = HR; +#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_POST(pointer,label,HR) ; goto label; } + +#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_LOGGER(pointer,label,HR) WPP_LEVEL_LOGGER( DMFT_INIT ) +#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_ENABLED(pointer,label,HR) WPP_CHECK_LEVEL_ENABLED( DMFT_INIT, TP_ERROR ) + +#define WPP_CHECKHRGOTO_EXP_LABEL_PRE(HR,label) if( FAILED( hr = HR ) ) { +#define WPP_CHECKHRGOTO_EXP_LABEL_POST(HR,label) ; goto label; } + +#define WPP_CHECKHRGOTO_EXP_LABEL_LOGGER(HR, label) WPP_LEVEL_LOGGER( DMFT_INIT ) +#define WPP_CHECKHRGOTO_EXP_LABEL_ENABLED(HR, label) WPP_CHECK_LEVEL_ENABLED( DMFT_INIT, TP_ERROR ) + + +// Give it checkhr and checknull definitions if some future generations of visual studio remove the wpp processor support + +//#if !defined DMFTCHECKHR_GOTO +//#define DMFTCHECKHR_GOTO(a,b) {hr=(a); if(FAILED(hr)){goto b;}} +//#endif +// +//#if !defined DMFTCHECKNULL_GOTO +//#define DMFTCHECKNULL_GOTO(a,b,c) {if(!a) {hr = c; goto b;}} +//#endif + +#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 SAFE_CLOSEHANDLE(h) { if(INVALID_HANDLE_VALUE != (h)) { ::CloseHandle(h); (h) = INVALID_HANDLE_VALUE; } } + + +#define SAFERELEASE(x) \ +if (x) {\ + x->Release(); \ + x = NULL; \ +} + +#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_) + +//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(); +}; + +class MediaBufferLock +{ +public: + MediaBufferLock(_In_ IMFMediaBuffer* pBuffer) : + m_bLocked(false) + { + m_spBuffer = pBuffer; + } + + HRESULT LockBuffer( + _Outptr_result_bytebuffer_to_(*pcbMaxLength, *pcbCurrentLength) BYTE** ppbBuffer, + _Out_opt_ DWORD* pcbMaxLength, + _Out_opt_ DWORD* pcbCurrentLength) + { + if (!m_spBuffer) + { + return E_INVALIDARG; + } + + HRESULT hr = m_spBuffer->Lock(ppbBuffer, pcbMaxLength, pcbCurrentLength); + if (FAILED(hr)) + { + return hr; + } + m_bLocked = true; + return S_OK; + } + + ~MediaBufferLock() + { + if (m_spBuffer && m_bLocked) + { + //Unlock fails only if we did not lock it first + (void)m_spBuffer->Unlock(); + } + } + +private: + ComPtr<IMFMediaBuffer> m_spBuffer; + bool m_bLocked; +}; + +typedef std::vector<ComPtr<IMFMediaType>> IMFMediaTypeArray; +typedef std::vector<ComPtr<CBasePin>> CBasePinArray; +typedef std::vector<ComPtr<IMFSample>> IMFSampleList; +typedef std::pair< std::multimap<int, int>::iterator, std::multimap<int, int>::iterator > MMFTMMAPITERATOR; + +STDMETHODIMP_(BOOL) IsPinStateInActive( + _In_ DeviceStreamState state + ); + + +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_UNEXPECTED; + } +} + +// +// 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; +}; + +class CPinQueue : public IUnknown +{ +public: + CPinQueue(_In_ DWORD _inPinId, _In_ IMFDeviceTransform* pTransform = nullptr); + ~CPinQueue(); + + STDMETHODIMP Insert(_In_ IMFSample* pSample); + STDMETHODIMP Remove(_Outptr_result_maybenull_ IMFSample** pSample); + STDMETHODIMP_(VOID) Clear(); + + // + // Inline functions + // + __inline BOOL Empty() + { + return (!m_sampleList.size()); + } + __inline DWORD pinStreamId() + { + return m_dwInPinId; + } + __inline GUID pinCategory() + { + if (IsEqualCLSID(m_streamCategory, GUID_NULL)) + { + ComPtr<IMFAttributes> spAttributes; + if (SUCCEEDED(m_pTransform->GetOutputStreamAttributes(pinStreamId(), spAttributes.ReleaseAndGetAddressOf()))) + { + (VOID) spAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &m_streamCategory); + } + } + return m_streamCategory; + } + + STDMETHODIMP QueryInterface(REFIID riid, void** ppv) + { + HRESULT hr = S_OK; + if (ppv != nullptr) + { + *ppv = nullptr; + if (riid == __uuidof(IUnknown)) + { + AddRef(); + *ppv = static_cast<IUnknown*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + else + { + hr = E_POINTER; + } + return hr; + } + + STDMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&m_cRef); + } + STDMETHODIMP_(ULONG) Release() + { + long cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) + { + delete this; + } + return cRef; + } + +private: + DWORD m_dwInPinId; /* This is the input pin */ + IMFSampleList m_sampleList; /* List storing the samples */ + IMFDeviceTransform* m_pTransform; /* Weak reference to the the device MFT */ + GUID m_streamCategory; + ULONG m_cRef; +}; + + +HRESULT ProcessMetadata(_In_ IMFSample* pSample); +// Metadata defintions + diff --git a/avstream/avscamera/DMFT/dllmain.cpp b/avstream/avscamera/DMFT/dllmain.cpp new file mode 100644 index 00000000..5a988320 --- /dev/null +++ b/avstream/avscamera/DMFT/dllmain.cpp @@ -0,0 +1,354 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +////////////////////////////////////////////////////////////////////////// +// +// 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" + +#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_AvsCameraDMFT, 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 +// + +IFACEMETHODIMP_(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; +} + +IFACEMETHODIMP 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); +} + +IFACEMETHODIMP DllRegisterServer() +{ + assert(g_hModule != NULL); + + // Register the CLSID for CoCreateInstance. + HRESULT hr = RegisterObject(g_hModule, CLSID_AvsCameraDMFT, TEXT("Multiple MFTs"), TEXT("Both")); + + return hr; +} + +IFACEMETHODIMP DllUnregisterServer() +{ + // Unregister the CLSID. + UnregisterObject(CLSID_AvsCameraDMFT); + + return S_OK; +} + + +// Converts a CLSID into a string with the form "CLSID\{clsid}" +IFACEMETHODIMP 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 +IFACEMETHODIMP 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/avscamera/DMFT/mftpeventgenerator.cpp b/avstream/avscamera/DMFT/mftpeventgenerator.cpp new file mode 100644 index 00000000..1e510cfa --- /dev/null +++ b/avstream/avscamera/DMFT/mftpeventgenerator.cpp @@ -0,0 +1,234 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" +#include "common.h" +#include "mftpeventgenerator.h" + + + +#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; + } + + return hr; +} + +// +// IMediaEventGenerator methods +// +STDMETHODIMP CMediaEventGenerator::BeginGetEvent( + _In_ IMFAsyncCallback* pCallback, + _In_ IUnknown* pState + ) +{ + HRESULT hr = S_OK; + 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; + 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; + 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; + 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; + + + m_critSec.Lock(); + + hr = CheckShutdown(); + + if (SUCCEEDED(hr)) + { + if (m_pQueue) + { + hr = m_pQueue->Shutdown(); + } + SAFE_RELEASE(m_pQueue); + m_bShutdown = TRUE; + } + m_critSec.Unlock(); + + return hr; +} + +STDMETHODIMP CMediaEventGenerator::QueueEvent( + _In_ IMFMediaEvent* pEvent + ) +{ + HRESULT hr = S_OK; + 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(); +} diff --git a/avstream/avscamera/DMFT/mftpeventgenerator.h b/avstream/avscamera/DMFT/mftpeventgenerator.h new file mode 100644 index 00000000..2ddae218 --- /dev/null +++ b/avstream/avscamera/DMFT/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/avscamera/DMFT/packages.config b/avstream/avscamera/DMFT/packages.config new file mode 100644 index 00000000..26065b14 --- /dev/null +++ b/avstream/avscamera/DMFT/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.210204.1" targetFramework="native" /> +</packages>
\ No newline at end of file diff --git a/avstream/avscamera/DMFT/stdafx.h b/avstream/avscamera/DMFT/stdafx.h new file mode 100644 index 00000000..d21def93 --- /dev/null +++ b/avstream/avscamera/DMFT/stdafx.h @@ -0,0 +1,47 @@ +// +// 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 <algorithm> +#include <new> +#include <d3d11_4.h> +#include <vector> +#include <map> +#include <stdexcept> +using namespace std; +#include <Windows.Foundation.h> +#include <wrl\client.h> +using namespace ABI::Windows::Foundation; +using namespace Microsoft::WRL; + +#include "common.h" +#include "AvsCameraDMFT.h" +#include "basepin.h" +#include "metadataInternal.h" diff --git a/avstream/avscamera/DMFT/stdafxsrc.cpp b/avstream/avscamera/DMFT/stdafxsrc.cpp new file mode 100644 index 00000000..a6f44b0e --- /dev/null +++ b/avstream/avscamera/DMFT/stdafxsrc.cpp @@ -0,0 +1,4 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "stdafx.h"
\ No newline at end of file |
