diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp new file mode 100644 index 000000000..e12cff652 --- /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 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 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 spInAttributes; + ComPtr 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 spInPin = (CInPin*)m_InPins[ulIndex].Get(); + + if (spInPin.Get()) + { + ComPtr spOutPin; + ComPtr 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 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 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 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 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 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 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 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 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 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 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 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 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 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::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 spoPin = GetOutPin(pinId); + ComPtr spinPin; + DeviceStreamState oldOutPinState, oldInputStreamState, newOutStreamState, newRequestedInPinState; + ComPtr 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 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 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(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 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 000000000..27b8607b5 --- /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 m_spDeviceManagerUnk; // D3D Manager set, when MFT_MESSAGE_SET_D3D_MANAGER is called through ProcessMessage + ComPtr m_spSourceTransform; // The sources transform. This is the pipeline DevProxy + MFSHUTDOWN_STATUS m_eShutdownStatus; + DWORD m_dwWorkQueueId; + LONG m_lWorkQueuePriority; + UINT32 m_punValue; + ComPtr m_spIkscontrol; + ComPtr m_spAttributes; + map 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.sln b/avstream/avscamera/DMFT/AvsCameraDMFT.sln new file mode 100644 index 000000000..95b0ed29e --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34009.444 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AvsCameraDMFT", "AvsCameraDMFT.vcxproj", "{E77657CD-A270-49E1-823A-8A14FF8596C8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|ARM64.Build.0 = Debug|ARM64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.ActiveCfg = Debug|ARM64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.Build.0 = Debug|ARM64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|ARM64.ActiveCfg = Release|ARM64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|ARM64.Build.0 = Release|ARM64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.ActiveCfg = Release|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {14EC00DC-D701-45EF-B1A1-6240AF128AD8} + EndGlobalSection +EndGlobal diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj new file mode 100644 index 000000000..3f6180f26 --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj @@ -0,0 +1,250 @@ + + + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + x64 + + + Release + x64 + + + + {E77657CD-A270-49E1-823A-8A14FF8596C8} + $(MSBuildProjectName) + false + Debug + Win32 + {D6CB33D6-DEF2-497E-A72D-6E6E29C67F48} + AvsCameraDMFT + $(LatestTargetPlatformVersion) + + + + Windows10 + False + Universal + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Universal + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + False + Universal + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + Windows10 + True + Universal + + WindowsApplicationForDrivers10.0 + DynamicLibrary + + + + $(IntDir) + + + + + + + + + + + + + + + + true + true + DMFTRACE(FLAG,LEVEL,MSG,...) + {um-default.tpl}*.tmh + ;%(AdditionalIncludeDirectories) + stdafx.h + Use + $(IntDir)\stdafx.h.pch + common.h + + + true + true + DMFTRACE(FLAG,LEVEL,MSG,...) + {um-default.tpl}*.tmh + ;%(AdditionalIncludeDirectories) + stdafx.h + Use + $(IntDir)\stdafx.h.pch + common.h + + + true + true + DMFTRACE(FLAG,LEVEL,MSG,...) + {um-default.tpl}*.tmh + ;%(AdditionalIncludeDirectories) + stdafx.h + Use + $(IntDir)\stdafx.h.pch + common.h + + + true + true + DMFTRACE(FLAG,LEVEL,MSG,...) + {um-default.tpl}*.tmh + ;%(AdditionalIncludeDirectories) + stdafx.h + Use + $(IntDir)\stdafx.h.pch + common.h + + + true + true + DMFTRACE(FLAG,LEVEL,MSG,...) + {um-default.tpl}*.tmh + ;%(AdditionalIncludeDirectories) + stdafx.h + Use + $(IntDir)\stdafx.h.pch + common.h + + + + AvsCameraDMFT + $(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\wil\include + + + + Sync + + + + + Sync + + + + + Sync + + + + + Sync + + + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib + Source.def + + + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib + Source.def + + + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib + Source.def + + + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD + + + %(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib + Source.def + + + + + ;%(AdditionalIncludeDirectories) + stdafx.h + Create + $(IntDir)\stdafx.h.pch + + + + + + + + + + + + + + + + + + + + \ 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 000000000..c3679c843 --- /dev/null +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters @@ -0,0 +1,57 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;* + {39379DB7-5CE0-407A-A6D4-F2F23BB3BF3C} + + + h;hpp;hxx;hm;inl;inc;xsd + {05E63691-6953-4F79-BEC2-1CF881B618BA} + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml + {B10F4398-9892-4AA8-8653-E5A7F4726726} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ 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 000000000..4a4c75fce --- /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(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 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 spMetadata; + ComPtr spSample = pSample; + HRESULT hr = spSample->GetUnknown(MFSampleExtension_CaptureMetadata, IID_PPV_ARGS(spMetadata.ReleaseAndGetAddressOf())); + if (FAILED(hr)) + { + return hr; + } + + ComPtr 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(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 + (reinterpret_cast(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 +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 000000000..752ef2ea8 --- /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 000000000..e01783906 --- /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 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(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 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(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 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 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 000000000..8051188a4 --- /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 m_spAttributes; + ComPtr m_spIkscontrol; + DeviceStreamState m_state; + ComPtr 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 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 m_spSourceTransform; /*Source Transform i.e. DevProxy*/ + GUID m_stStreamType; /*GUID representing the GUID*/ + ComPtr 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 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 000000000..b6e636a87 --- /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 m_spBuffer; + bool m_bLocked; +}; + +typedef std::vector> IMFMediaTypeArray; +typedef std::vector> CBasePinArray; +typedef std::vector> IMFSampleList; +typedef std::pair< std::multimap::iterator, std::multimap::iterator > MMFTMMAPITERATOR; + +STDMETHODIMP_(BOOL) IsPinStateInActive( + _In_ DeviceStreamState state + ); + + +template +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 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(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 000000000..5a988320c --- /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" = + 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 000000000..1e510cfa2 --- /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(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 000000000..2ddae218f --- /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 000000000..26065b144 --- /dev/null +++ b/avstream/avscamera/DMFT/packages.config @@ -0,0 +1,4 @@ + + + + \ 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 000000000..d21def931 --- /dev/null +++ b/avstream/avscamera/DMFT/stdafx.h @@ -0,0 +1,47 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +#include +#include +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 000000000..a6f44b0e8 --- /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 diff --git a/avstream/avscamera/Package/package.VcxProj b/avstream/avscamera/Package/package.VcxProj index 32eb33549..a570a1fbb 100644 --- a/avstream/avscamera/Package/package.VcxProj +++ b/avstream/avscamera/Package/package.VcxProj @@ -19,8 +19,8 @@ - - {2C0B129E-88F3-479A-AE5D-65609A88BE66} + + {e77657cd-a270-49e1-823a-8a14ff8596c8} {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68} diff --git a/avstream/avscamera/README.md b/avstream/avscamera/README.md index da8e8d65b..2cfde98ce 100644 --- a/avstream/avscamera/README.md +++ b/avstream/avscamera/README.md @@ -15,7 +15,7 @@ The AvsCamera sample provides a pin-centric AVStream capture driver for a simula This sample features strong parameter validation and overflow detection. It provides validation and simulation logic for all advanced camera controls in the CCaptureFilter class. A real camera driver would replace the filter automation table and CSensor and CSynthesizer class hierarchies to produce a new camera driver. -The sample comes with its own MFT0 called AvsCameraMft0.dll. This MFT0 is used to parse metadata supplied in the AvsCamera driver samples. The metadata communications from the driver is primarily a private channel to its MFT0. The MFT0 is responsible for reformatting that information for the capture pipeline. +The sample comes with its own DeviceMFT called AvsCameraMft0.dll. This DeviceMFT is used to parse metadata supplied in the AvsCamera driver samples. The metadata communications from the driver is primarily a private channel to its DeviceMFT. The DeviceMFT is responsible for reformatting that information for the capture pipeline. ## Universal Windows Driver Compliant @@ -23,4 +23,4 @@ This sample builds a Universal Windows Driver. It uses only APIs and DDIs that a ## Building the sample -The AvsCamera sample can be built by opening the AvsCamera.sln solution file. A successful build produces AvsCamera.sys, AvsCameraMft0.dll, AvsCamera.inf and AvsCamera.cat. +The AvsCamera sample can be built by opening the AvsCamera.sln solution file. A successful build produces AvsCamera.sys, AvsCameraDMFT.dll, AvsCamera.inf and AvsCamera.cat. diff --git a/avstream/avscamera/avscamera.sln b/avstream/avscamera/avscamera.sln index faa04506b..b358cd908 100644 --- a/avstream/avscamera/avscamera.sln +++ b/avstream/avscamera/avscamera.sln @@ -1,59 +1,65 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34009.444 MinimumVisualStudioVersion = 12.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{174AB66C-6250-4DDB-88C5-856B9D499DB7}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mft0", "Mft0", "{8031E506-AE20-4995-9F28-2D177A1FB319}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{72571B45-7827-4380-8821-38A33FBFF4E2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{9397D285-8C29-4661-A741-F6703E2F5FD6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AvsCameraMft0", "mft0\AvsCameraMft0.vcxproj", "{2C0B129E-88F3-479A-AE5D-65609A88BE66}" + ProjectSection(ProjectDependencies) = postProject + {E77657CD-A270-49E1-823A-8A14FF8596C8} = {E77657CD-A270-49E1-823A-8A14FF8596C8} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AvsCamera", "sys\AvsCamera.vcxproj", "{24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AvsCameraDMFT", "DMFT\AvsCameraDMFT.vcxproj", "{E77657CD-A270-49E1-823A-8A14FF8596C8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DMFT", "DMFT", "{08C63CB6-78C2-44EC-AA24-8CBA0CFEE2E6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|Win32.ActiveCfg = Debug|Win32 {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|Win32.Build.0 = Debug|Win32 - {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|Win32.ActiveCfg = Release|Win32 - {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|Win32.Build.0 = Release|Win32 {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|x64.ActiveCfg = Debug|x64 {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|x64.Build.0 = Debug|x64 + {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|Win32.ActiveCfg = Release|Win32 + {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|Win32.Build.0 = Release|Win32 {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|x64.ActiveCfg = Release|x64 {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|x64.Build.0 = Release|x64 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|Win32.ActiveCfg = Debug|Win32 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|Win32.Build.0 = Debug|Win32 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|Win32.ActiveCfg = Release|Win32 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|Win32.Build.0 = Release|Win32 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|x64.ActiveCfg = Debug|x64 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|x64.Build.0 = Debug|x64 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|x64.ActiveCfg = Release|x64 - {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|x64.Build.0 = Release|x64 {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|Win32.ActiveCfg = Debug|Win32 {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|Win32.Build.0 = Debug|Win32 - {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|Win32.ActiveCfg = Release|Win32 - {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|Win32.Build.0 = Release|Win32 {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|x64.ActiveCfg = Debug|x64 {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|x64.Build.0 = Debug|x64 + {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|Win32.ActiveCfg = Release|Win32 + {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|Win32.Build.0 = Release|Win32 {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|x64.ActiveCfg = Release|x64 {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|x64.Build.0 = Release|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.ActiveCfg = Debug|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.Build.0 = Debug|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.ActiveCfg = Debug|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.Build.0 = Debug|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.ActiveCfg = Release|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.Build.0 = Release|Win32 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.ActiveCfg = Release|x64 + {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {9397D285-8C29-4661-A741-F6703E2F5FD6} = {174AB66C-6250-4DDB-88C5-856B9D499DB7} - {2C0B129E-88F3-479A-AE5D-65609A88BE66} = {8031E506-AE20-4995-9F28-2D177A1FB319} {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68} = {72571B45-7827-4380-8821-38A33FBFF4E2} + {E77657CD-A270-49E1-823A-8A14FF8596C8} = {08C63CB6-78C2-44EC-AA24-8CBA0CFEE2E6} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2191F306-963C-4507-99DB-A9D54CB8615B} EndGlobalSection EndGlobal diff --git a/avstream/avscamera/mft0/AvsCameraMFT0.rc b/avstream/avscamera/mft0/AvsCameraMFT0.rc deleted file mode 100644 index 86c06ba28..000000000 --- a/avstream/avscamera/mft0/AvsCameraMFT0.rc +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - - -#define VER_FILETYPE VFT_DLL -#define VER_FILESUBTYPE VFT2_UNKNOWN -#define VER_FILEDESCRIPTION_STR "A/V Stream Camera MFT0" -#define VER_INTERNALNAME_STR "AvsCameraMft0.dll" -#define VER_ORIGINALFILENAME_STR "AvsCameraMft0.dll" -#define VER_LANGNEUTRAL - -#include "common.ver" - diff --git a/avstream/avscamera/mft0/AvsCameraMft0.vcxproj b/avstream/avscamera/mft0/AvsCameraMft0.vcxproj deleted file mode 100644 index f1c67d95a..000000000 --- a/avstream/avscamera/mft0/AvsCameraMft0.vcxproj +++ /dev/null @@ -1,216 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {2C0B129E-88F3-479A-AE5D-65609A88BE66} - $(MSBuildProjectName) - false - true - Debug - Win32 - {1921F93C-296D-4875-BD67-D087F1DBF95B} - - - - Windows10 - False - Windows Driver - - WindowsApplicationForDrivers10.0 - DynamicLibrary - - - Windows10 - True - Windows Driver - - WindowsApplicationForDrivers10.0 - DynamicLibrary - - - Windows10 - False - Windows Driver - - WindowsApplicationForDrivers10.0 - DynamicLibrary - - - Windows10 - True - Windows Driver - - WindowsApplicationForDrivers10.0 - DynamicLibrary - - - - $(IntDir) - - - - - - - - - - - - - - - - AvsCameraMft0 - - - AvsCameraMft0 - - - AvsCameraMft0 - - - AvsCameraMft0 - - - - Sync - - - - - Sync - - - - - Sync - - - - - Sync - - - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - %(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common - - - - - %(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib - Mft0.def - - - - - %(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib - Mft0.def - - - - - %(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib - Mft0.def - - - - - %(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib - Mft0.def - - - - - - ;%(AdditionalIncludeDirectories) - stdafx.h - Use - $(IntDir)\stdafx.h.pch - - - ;%(AdditionalIncludeDirectories) - stdafx.h - Use - $(IntDir)\stdafx.h.pch - - - ;%(AdditionalIncludeDirectories) - stdafx.h - Create - $(IntDir)\stdafx.h.pch - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/avstream/avscamera/mft0/MFT0.def b/avstream/avscamera/mft0/MFT0.def deleted file mode 100644 index b4430ceb3..000000000 --- a/avstream/avscamera/mft0/MFT0.def +++ /dev/null @@ -1,13 +0,0 @@ -; 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 - -; SampleMft0.def : Declares the module parameters. - -LIBRARY - -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE \ No newline at end of file diff --git a/avstream/avscamera/mft0/MFT0.idl b/avstream/avscamera/mft0/MFT0.idl deleted file mode 100644 index 40098f71f..000000000 --- a/avstream/avscamera/mft0/MFT0.idl +++ /dev/null @@ -1,46 +0,0 @@ -//// 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 - -// SampleMft0.idl : IDL source for SampleMft0 -// - -// This file will be processed by the MIDL tool to -// produce the type library (SampleMft0.tlb) and marshalling code. - -import "oaidl.idl"; -import "ocidl.idl"; -import "Inspectable.idl"; -import "mftransform.idl"; -[ - object, - uuid(7B917902-D657-4437-9F93-93B94482F286), - oleautomation, - nonextensible, - pointer_default(unique) -] -interface ISocMft0 : IUnknown{ - [id(1)] HRESULT SetState([in] UINT32 state); - [id(2)] HRESULT GetState([out] UINT* pState); -}; -[ - uuid(8F14E328-2084-442E-A4D9-A80AA30ECBA8), - version(1.0), -] -library SampleSocMft0Lib -{ - importlib("stdole2.tlb"); - [ - uuid(424BF154-D92A-42EB-B041-1395F9E5B4A2) - ] - coclass Mft0 - { - [default] interface ISocMft0; - interface IInspectable; - interface IMFTransform; - }; -}; - diff --git a/avstream/avscamera/mft0/MFT0Impl.cpp b/avstream/avscamera/mft0/MFT0Impl.cpp deleted file mode 100644 index 26d40f997..000000000 --- a/avstream/avscamera/mft0/MFT0Impl.cpp +++ /dev/null @@ -1,2083 +0,0 @@ -/************************************************************************** - - A/V Stream Camera Sample - - Copyright (c) 2014, Microsoft Corporation. - - File: - - Mft0Impl.cpp - - Abstract: - - This is the implementation of CSocMft0. - - CSocMft0 is the MFT0 for the AvsCamera sample driver. This MFT0 - performs the following key tasks: - 1. Filters overscan media types supplied by the driver, and - 2. Parses private metadata and attaches an IMFAttribute to the sample. - - History: - - created 5/15/2014 - -**************************************************************************/ - - -#include "stdafx.h" -#include "Mft0Impl.h" -#include "SampleHelpers.h" -#include "metadataInternal.h" -#include -#include -#include -#include - -#include "CustomProperties.h" -#include "macros.h" - -///////////////////////////////////////////////////////////////////////////////// -// -// These two functions demostrate that OEM application can communicate with MFT0 -// -STDMETHODIMP CSocMft0::SetState(UINT32 state) -{ - // OEM can use similar function to update the status of MFT - // From their own application - m_uiInternalState = state; - return S_OK; -} - -STDMETHODIMP CSocMft0::GetState(UINT32 *pState) -{ - HRESULT hr = S_OK; - - // OEM can use similar function to get the status of MFT - // From their own application - if (!pState) - { - return E_POINTER; - } - *pState = m_uiInternalState; - - return hr; -} - -////////////////////////////////////////////////////////////////////////////////// -// -// This initializes the CSocMFT0 for Com -// -// -HRESULT CSocMft0::CreateInstance( - REFIID iid, - void **ppMFT -) -{ - HRESULT hr = S_OK; - ComPtr spMFT; - UNREFERENCED_PARAMETER(iid); - - auto sObject = Microsoft::WRL::Make(); - - if (!sObject) - { - return E_OUTOFMEMORY; - } - hr = sObject->FinalConstruct(); - - if (SUCCEEDED(hr)) - { - hr = sObject.As(&spMFT); - *ppMFT = spMFT.Detach(); - } - - return hr; -} - -///////////////////////////////////////////////////////////////////////////////// -// -// IInspectable interface enable COM interface to talk with other programming environments -// -// Gets the interfaces that are implemented by the current Windows Runtime class. -// -STDMETHODIMP CSocMft0::GetIids( - _Out_ ULONG *iidCount, - _Outptr_result_buffer_maybenull_(*iidCount) IID **iids -) -{ - HRESULT hr = S_OK; - - if (!iidCount) - { - return E_POINTER; - } - - if (!iids) - { - return E_POINTER; - } - - *iids = NULL; - *iidCount = 0; - - return hr; -} - -///////////////////////////////////////////////////////////////////////////////// -// -// Gets the fully qualified name of the current Windows Runtime object. -// -STDMETHODIMP CSocMft0::GetRuntimeClassName( - _Outptr_result_maybenull_ HSTRING *pClassName -) -{ - - if (!pClassName) - { - return E_POINTER; - } - return WindowsCreateString(NULL, 0, pClassName); -} - -///////////////////////////////////////////////////////////////////////////////// -// -// Gets the trust level of the current Windows Runtime object. -// -STDMETHODIMP CSocMft0::GetTrustLevel( - _Out_ TrustLevel *trustLevel -) -{ - HRESULT hr = S_OK; - - if (trustLevel) - { - return E_POINTER; - } - *trustLevel = TrustLevel::BaseTrust; - - return hr; -} - -//////////////////////////////////////////////////////////////////////// -// -// Final Construct -// -HRESULT CSocMft0::FinalConstruct() -{ - HRESULT hr = S_OK; - hr = MFCreateAttributes(&m_spGlobalAttributes, 3); - if (FAILED(hr)) - { - goto done; - } - - hr = m_spGlobalAttributes->SetUINT32(MF_TRANSFORM_ASYNC, FALSE); - if (FAILED(hr)) - { - goto done; - } - - hr = m_spGlobalAttributes->SetString( - MFT_ENUM_HARDWARE_URL_Attribute, - L"Sample_CameraExtensionMft"); - if (FAILED(hr)) - { - goto done; - } - - hr = m_spGlobalAttributes->SetUINT32( - MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, - TRUE); - -done: - if (FAILED(hr)) - { - m_spGlobalAttributes.Reset(); - } - return hr; -} - -// IMFTransform methods. Refer to the Media Foundation SDK documentation for details. - -//////////////////////////////////////////////////////////////////////// -// -// GetStreamLimits -// Returns the minimum and maximum number of streams. -// -STDMETHODIMP CSocMft0::GetStreamLimits( - _Out_ DWORD *pdwInputMinimum, - _Out_ DWORD *pdwInputMaximum, - _Out_ DWORD *pdwOutputMinimum, - _Out_ DWORD *pdwOutputMaximum -) -{ - if ((!pdwInputMinimum) || - (!pdwInputMaximum) || - (!pdwOutputMinimum) || - (!pdwOutputMaximum)) - { - return E_POINTER; - } - - // This MFT has a fixed number of streams. - *pdwInputMinimum = 1; - *pdwInputMaximum = 1; - *pdwOutputMinimum = 1; - *pdwOutputMaximum = 1; - - return S_OK; -} - -//////////////////////////////////////////////////////////////////////// -// -// GetStreamCount -// Returns the actual number of streams. -// -STDMETHODIMP CSocMft0::GetStreamCount( - _Out_ DWORD *pcInputStreams, - _Out_ DWORD *pcOutputStreams -) -{ - if (!pcInputStreams || !pcOutputStreams) - { - return E_POINTER; - } - - // This MFT has a fixed number of streams. - *pcInputStreams = 1; - *pcOutputStreams = 1; - - return S_OK; -} - -//////////////////////////////////////////////////////////////////////// -// -// GetStreamIDs -// Returns stream IDs for the input and output streams. -// -STDMETHODIMP CSocMft0::GetStreamIDs( - DWORD dwInputIDArraySize, - _Out_writes_(dwInputIDArraySize) DWORD *pdwInputIDs, - DWORD dwOutputIDArraySize, - _Out_writes_(dwOutputIDArraySize) DWORD *pdwOutputIDs -) -{ - UNREFERENCED_PARAMETER(dwInputIDArraySize); - UNREFERENCED_PARAMETER(dwOutputIDArraySize); - UNREFERENCED_PARAMETER(pdwInputIDs); - UNREFERENCED_PARAMETER(pdwOutputIDs); - - // It is not required to implement this method if the MFT has a fixed number of - // streams AND the stream IDs are numbered sequentially from zero (that is, the - // stream IDs match the stream indexes). - - // In that case, it is OK to return E_NOTIMPL. - return (E_NOTIMPL); -} - -//////////////////////////////////////////////////////////////////////// -// -// GetInputStreamInfo -// Returns information about an input stream. -// -STDMETHODIMP CSocMft0::GetInputStreamInfo( - DWORD dwInputStreamID, - _Out_ MFT_INPUT_STREAM_INFO *pStreamInfo -) -{ - UNREFERENCED_PARAMETER(dwInputStreamID); - CAutoLock lock(&m_critSec); - - if (!pStreamInfo) - { - return E_POINTER; - } - - if (!m_spInputType) - { - return MF_E_TRANSFORM_TYPE_NOT_SET; - } - - pStreamInfo->hnsMaxLatency = 0; - pStreamInfo->cbAlignment = 0; - pStreamInfo->cbSize = 0; - pStreamInfo->dwFlags = - MFT_INPUT_STREAM_WHOLE_SAMPLES | - MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | - MFT_INPUT_STREAM_PROCESSES_IN_PLACE; - pStreamInfo->hnsMaxLatency = 0; - - return S_OK; -} - -//////////////////////////////////////////////////////////////////////// -// -// GetOutputStreamInfo -// Returns information about an output stream. -// -STDMETHODIMP CSocMft0::GetOutputStreamInfo( - DWORD dwOutputStreamID, - _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo -) -{ - UNREFERENCED_PARAMETER(dwOutputStreamID); - CAutoLock lock(&m_critSec); - - if (!pStreamInfo) - { - return E_POINTER; - } - - if (!m_spOutputType) - { - return MF_E_TRANSFORM_TYPE_NOT_SET; - } - - pStreamInfo->cbAlignment = 0; - pStreamInfo->cbSize = 0; - pStreamInfo->dwFlags = - MFT_OUTPUT_STREAM_WHOLE_SAMPLES | - MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | - MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | - MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; - - return S_OK; -} - -///////////////////////////////////////////////////////////////////////// -// -// GetAttributes -// Returns the global attributes for the MFT. -// -STDMETHODIMP CSocMft0::GetAttributes( - _Outptr_result_maybenull_ IMFAttributes **ppAttributes -) -{ - if (!ppAttributes) - { - return E_POINTER; - } - - return m_spGlobalAttributes.CopyTo(ppAttributes); -} - -//////////////////////////////////////////////////////////////////////// -// -// GetInputStreamAttributes -// Returns stream-level attributes for an input stream. -// -STDMETHODIMP CSocMft0::GetInputStreamAttributes( - DWORD dwInputStreamID, - _Outptr_result_maybenull_ IMFAttributes **ppAttributes -) -{ - HRESULT hr = S_OK; - - if (dwInputStreamID > 0) - { - return MF_E_INVALIDSTREAMNUMBER; - } - if (!ppAttributes) - { - return E_POINTER; - } - - if (!m_spInputAttributes) - { - hr = MFCreateAttributes(&m_spInputAttributes, 2); - if (FAILED(hr)) - { - goto done; - } - hr = m_spInputAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE); - if (FAILED(hr)) - { - goto done; - } - hr = m_spInputAttributes->SetString(MFT_ENUM_HARDWARE_URL_Attribute, L"Sample_CameraExtensionMft"); - if (FAILED(hr)) - { - goto done; - } - } - hr = m_spInputAttributes.CopyTo(ppAttributes); - -done: - if (FAILED(hr)) - { - m_spInputAttributes.Reset(); - } - return hr; -} - -//////////////////////////////////////////////////////////////////////// -// -// GetOutputStreamAttributes -// Returns stream-level attributes for an output stream. -// -STDMETHODIMP CSocMft0::GetOutputStreamAttributes( - DWORD dwOutputStreamID, - _Outptr_result_maybenull_ IMFAttributes **ppAttributes -) -{ - if (dwOutputStreamID > 0) - { - return MF_E_INVALIDSTREAMNUMBER; - } - - if (!ppAttributes) - { - return E_POINTER; - } - - if (!m_spInputAttributes) - { - return MF_E_TRANSFORM_TYPE_NOT_SET; - } - - return m_spInputAttributes.CopyTo(ppAttributes); -} - -//////////////////////////////////////////////////////////////////////// -// -// DeleteInputStream -// -STDMETHODIMP CSocMft0::DeleteInputStream( - DWORD dwStreamID -) -{ - UNREFERENCED_PARAMETER(dwStreamID); - - // This MFT has a fixed number of input streams, so the method is not supported. - return (E_NOTIMPL); -} - -//////////////////////////////////////////////////////////////////////// -// -// AddInputStreams -// -STDMETHODIMP CSocMft0::AddInputStreams( - DWORD cStreams, - _In_ DWORD *adwStreamIDs -) -{ - UNREFERENCED_PARAMETER(cStreams); - UNREFERENCED_PARAMETER(adwStreamIDs); - - // This MFT has a fixed number of output streams, so the method is not supported. - return (E_NOTIMPL); -} - -//////////////////////////////////////////////////////////////////////// -// -// GetInputAvailableType -// Returns a preferred input type. -// -STDMETHODIMP CSocMft0::GetInputAvailableType( - DWORD dwInputStreamID, - DWORD dwTypeIndex, - _Outptr_result_maybenull_ IMFMediaType **ppType -) -{ - HRESULT hr = S_OK; - ComPtr spUnknown; - ComPtr spSourceAttributes; - - CAutoLock lock(&m_critSec); - - if (!m_spSourceTransform && m_spInputAttributes) - { - hr = m_spInputAttributes->GetUnknown(MFT_CONNECTED_STREAM_ATTRIBUTE, IID_PPV_ARGS(spSourceAttributes.ReleaseAndGetAddressOf())); - if (FAILED(hr)) - { - return hr; - } - - hr = spSourceAttributes->GetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT, IID_PPV_ARGS(spUnknown.ReleaseAndGetAddressOf())); - if (FAILED(hr)) - { - return hr; - } - - hr = spUnknown.As(&m_spSourceTransform); - if (FAILED(hr)) - { - return hr; - } - - hr = spSourceAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType); - if (FAILED(hr)) - { - return hr; - } - - hr = spSourceAttributes->GetUINT32(MF_DEVICESTREAM_STREAM_ID, &m_uiSourceStreamId); - if (FAILED(hr)) - { - return hr; - } - - hr = GenerateMFMediaTypeListFromDevice(); - if (FAILED(hr)) - { - return hr; - } - } - - hr = GetMediaType(dwInputStreamID, dwTypeIndex, ppType); - - return hr; -} - -//////////////////////////////////////////////////////////////////////// -// -// GetOutputAvailableType -// Returns a preferred output type. -// -STDMETHODIMP CSocMft0::GetOutputAvailableType( - DWORD dwOutputStreamID, - DWORD dwTypeIndex, - _Outptr_result_maybenull_ IMFMediaType **ppType -) -{ - HRESULT hr = S_OK; - ComPtr spUnknown; - ComPtr spSourceAttributes; - - CAutoLock lock(&m_critSec); - - if (!m_spSourceTransform && m_spInputAttributes) - { - hr = m_spInputAttributes->GetUnknown(MFT_CONNECTED_STREAM_ATTRIBUTE, IID_PPV_ARGS(spSourceAttributes.ReleaseAndGetAddressOf())); - if (FAILED(hr)) - { - return hr; - } - - hr = spSourceAttributes->GetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT, IID_PPV_ARGS(spUnknown.ReleaseAndGetAddressOf())); - if (FAILED(hr)) - { - return hr; - } - - hr = spUnknown.As(&m_spSourceTransform); - if (FAILED(hr)) - { - return hr; - } - - hr = spSourceAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType); - if (FAILED(hr)) - { - return hr; - } - - hr = spSourceAttributes->GetUINT32(MF_DEVICESTREAM_STREAM_ID, &m_uiSourceStreamId); - if (FAILED(hr)) - { - return hr; - } - - // - // This is the first function get called after the MFT0 object get instantiated, - // Here we can generate the supported media type from the connected input pin, - // Also, we can selectively plug in MFT0 only on pins requires processing - // by returning error on the unwanted pin types. Example below if we did not - // want MFT0 for Record - - //if(m_stStreamType != PINNAME_IMAGE && m_stStreamType != PINNAME_VIDEO_PREVIEW) - //{ - // return E_UNEXPECTED; - //} - - hr = GenerateMFMediaTypeListFromDevice(); - if (FAILED(hr)) - { - return hr; - } - } - - return GetMediaType(dwOutputStreamID, dwTypeIndex, ppType); -} - -//////////////////////////////////////////////////////////////////////// -// -// SetInputType -// -STDMETHODIMP CSocMft0::SetInputType( - DWORD dwInputStreamID, - _In_opt_ IMFMediaType *pType, - DWORD dwFlags -) -{ - HRESULT hr = S_OK; - - CAutoLock lock(&m_critSec); - - BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0); - - // Validate flags. - // Only MFT_SET_TYPE_TEST_ONLY is supported, if any other bit flags - // get set, it should return error. - if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY) - { - return E_INVALIDARG; - } - - if (!bReallySet) - { - return IsMediaTypeSupported(dwInputStreamID, pType); - } - - ComPtr spFullType; - hr = IsMediaTypeSupported(dwInputStreamID, pType, spFullType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - return hr; - } - - m_spInputType = spFullType; - - return S_OK; -} - -//////////////////////////////////////////////////////////////////////// -// -// SetOutputType -// This function set the output media type and at the same time, it should -// also choose a compatible input type -// -STDMETHODIMP CSocMft0::SetOutputType( - DWORD dwOutputStreamID, - _In_opt_ IMFMediaType *pType, - DWORD dwFlags -) -{ - HRESULT hr = S_OK; - - CAutoLock lock(&m_critSec); - BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0); - BOOL bUseModifiedInputType = FALSE; - - // Validate flags. - if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY) - { - return E_INVALIDARG; - } - - if (!bReallySet) - { - return IsMediaTypeSupported(dwOutputStreamID, pType); - } - - ComPtr spFullType; - ComPtr spFullInputType; - hr = IsMediaTypeSupported(dwOutputStreamID, pType, spFullType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - return hr; - } - - if (m_stStreamType == PINNAME_CAPTURE) - { - hr = GetVideoStabilizationEnabled(); - if (FAILED(hr)) - { - return hr; - } - - // Hardware Video Stabilization is enabled - if (m_bEnableVideoStabilization) - { - UINT32 uiIndex = 0; - //This shouldn't fail, since it is derived from IsMediaTypeSupported - // and that just passed. - hr = FindMediaIndex(dwOutputStreamID, pType, &uiIndex); - if (FAILED(hr)) - { - return hr; - } - //Device Driver contains a static list of mediatypes on the pin - // We have ordered them in such a way so that all odd mediatypes are the - // overscan media of the even mediatype immediatley proceeding it, ie. - // -normalVGA - // -overscanVGA - // -normalQVGA - // -overscanQVGA - // etc - // The following command determines if we are dealing with an overscan or normal mediatype - // if it is overscan, we fail (cannot overscan an overscan mediatype) - // otherwise, we set our input mediatype to the overscan type associated with it. - if (uiIndex % 2 != 0) //odd means overscan - { - return MF_E_INVALIDMEDIATYPE; - } - else //even - { - hr = GetMediaType(dwOutputStreamID, uiIndex + 1, spFullInputType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - return hr; - } - - bUseModifiedInputType = TRUE; - } - } - } - m_spOutputType = spFullType; - - // Here, we choose a compatible input type which is the same type - // as output. If OEM choose to encode sample here, it should choose - // an input which is supported by encoder. - if (bUseModifiedInputType) - { - m_spInputType = spFullInputType; - } - else - { - m_spInputType = spFullType; - } - - return S_OK; -} - -//////////////////////////////////////////////////////////////////////// -// -// GetInputCurrentType -// Returns the current input type. -// -STDMETHODIMP CSocMft0::GetInputCurrentType( - DWORD dwInputStreamID, - _Outptr_result_maybenull_ IMFMediaType **ppType -) -{ - UNREFERENCED_PARAMETER(dwInputStreamID); - HRESULT hr = S_OK; - - CAutoLock lock(&m_critSec); - - if (!ppType) - { - return E_POINTER; - } - - if (!m_spInputType) - { - return MF_E_TRANSFORM_TYPE_NOT_SET; - } - - ComPtr spMediaType; - hr = MFCreateMediaType(spMediaType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - return hr; - } - - hr = m_spInputType->CopyAllItems(spMediaType.Get()); - if (FAILED(hr)) - { - return hr; - } - - return spMediaType.CopyTo(ppType); -} - -//////////////////////////////////////////////////////////////////////// -// -// GetOutputCurrentType -// Returns the current output type. -// -STDMETHODIMP CSocMft0::GetOutputCurrentType( - DWORD dwOutputStreamID, - _Outptr_result_maybenull_ IMFMediaType **ppType -) -{ - UNREFERENCED_PARAMETER(dwOutputStreamID); - HRESULT hr = S_OK; - - CAutoLock lock(&m_critSec); - - if (!ppType) - { - return E_POINTER; - } - - if (!m_spOutputType) - { - return MF_E_TRANSFORM_TYPE_NOT_SET; - } - - ComPtr spMediaType; - hr = MFCreateMediaType(spMediaType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - return hr; - } - - hr = m_spOutputType->CopyAllItems(spMediaType.Get()); - if (FAILED(hr)) - { - return hr; - } - - return spMediaType.CopyTo(ppType); -} - -//////////////////////////////////////////////////////////////////////// -// -// GetInputStatus -// Query if the MFT is accepting more input. -// -STDMETHODIMP CSocMft0::GetInputStatus( - DWORD dwInputStreamID, - _Out_ DWORD *pdwFlags -) -{ - UNREFERENCED_PARAMETER(dwInputStreamID); - CAutoLock lock(&m_critSec); - - if (!pdwFlags) - { - return E_POINTER; - } - - // If we already have an input sample, we don't accept - // another one until the client calls ProcessOutput or Flush. - if (m_spSample == NULL) - { - *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA; - } - else - { - *pdwFlags = 0; - } - - return S_OK; -} - -//////////////////////////////////////////////////////////////////////// -// -// GetOutputStatus -// Query if the MFT can produce output. -// -STDMETHODIMP CSocMft0::GetOutputStatus( - _Out_ DWORD *pdwFlags -) -{ - if (!pdwFlags) - { - return E_POINTER; - } - - CAutoLock lock(&m_critSec); - - // We can produce an output sample if (and only if) - // we have an input sample. - if (m_spSample != NULL) - { - *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY; - } - else - { - *pdwFlags = 0; - } - - return S_OK; -} - -//////////////////////////////////////////////////////////////////////// -// -// SetOutputBounds -// Sets the range of time stamps that the MFT will output. -// -STDMETHODIMP CSocMft0::SetOutputBounds( - LONGLONG hnsLowerBound, - LONGLONG hnsUpperBound -) -{ - UNREFERENCED_PARAMETER(hnsLowerBound); - UNREFERENCED_PARAMETER(hnsUpperBound); - - // Implementation of this method is optional. - return (E_NOTIMPL); -} - -//////////////////////////////////////////////////////////////////////// -// -// ProcessEvent -// Sends an event to an input stream. -// -STDMETHODIMP CSocMft0::ProcessEvent( - DWORD dwInputStreamID, - _In_opt_ IMFMediaEvent *pEvent -) -{ - UNREFERENCED_PARAMETER(dwInputStreamID); - UNREFERENCED_PARAMETER(pEvent); - return E_NOTIMPL; -} - -//////////////////////////////////////////////////////////////////////// -// -// ProcessMessage -// -STDMETHODIMP CSocMft0::ProcessMessage( - MFT_MESSAGE_TYPE eMessage, - ULONG_PTR ulParam -) -{ - UNREFERENCED_PARAMETER(ulParam); - HRESULT hr = S_OK; - - CAutoLock lock(&m_critSec); - - switch (eMessage) - { - case MFT_MESSAGE_COMMAND_FLUSH: - // Flush the MFT. - hr = OnFlush(); - break; - } - - return hr; -} - -///////////////////////////////////////////////////////////////////// -// -// ProcessInput -// Process an input sample. The sample is cached and real work is done -// in ProcessOutput -// -STDMETHODIMP CSocMft0::ProcessInput( - DWORD dwInputStreamID, - IMFSample *pSample, - DWORD dwFlags -) -{ - UNREFERENCED_PARAMETER(dwInputStreamID); - HRESULT hr = S_OK; - - CAutoLock lock(&m_critSec); - - if (!pSample) - { - return E_POINTER; - } - if (dwFlags != 0) - { - return E_INVALIDARG; - } - - if (!m_spInputType || !m_spOutputType) - { - return MF_E_NOTACCEPTING; // Client must set input and output types. - } - - if (m_spSample != NULL) - { - return MF_E_NOTACCEPTING; // We already have an input sample. - } - - // Validate the number of buffers. There should only be a single buffer to hold the video frame. - DWORD dwBufferCount = 0; - hr = pSample->GetBufferCount(&dwBufferCount); - if (FAILED(hr)) - { - return hr; - } - - if (dwBufferCount == 0) - { - return E_FAIL; - } - - if (dwBufferCount > 1) - { - return MF_E_SAMPLE_HAS_TOO_MANY_BUFFERS; - } - - // Cache the sample. We do the actual work in ProcessOutput. - m_spSample = pSample; - - return S_OK; -} - -///////////////////////////////////////////////////////////////////// -// -// ProcessOutput -// Process an output sample. -// -STDMETHODIMP CSocMft0::ProcessOutput( - DWORD dwFlags, - DWORD cOutputBufferCount, - MFT_OUTPUT_DATA_BUFFER *pOutputSamples, - DWORD *pdwStatus -) -{ - HRESULT hr = S_OK; - - CAutoLock lock(&m_critSec); - - if (dwFlags != 0) - { - return E_INVALIDARG; - } - - if (!pOutputSamples || !pdwStatus) - { - return E_POINTER; - } - - if (pOutputSamples[0].pSample) - { - pOutputSamples[0].pSample->Release(); - pOutputSamples[0].pSample = nullptr; - } - - // Must be exactly one output buffer. - if (cOutputBufferCount != 1) - { - return E_INVALIDARG; - } - - // If we don't have an input sample, we need some input before - // we can generate any output. - if (m_spSample == nullptr) - { - return MF_E_TRANSFORM_NEED_MORE_INPUT; - } -#if (NTDDI_VERSION >= NTDDI_WINBLUE) - hr = ProcessMetadata(); - if (FAILED(hr)) - { - //Log the failure - hr = S_OK; - } -#endif // (NTDDI_VERSION >= NTDDI_WINBLUE) - hr = CreateOutputSample(&pOutputSamples[0].pSample); - if (FAILED(hr)) - { - return hr; - } - pOutputSamples[0].dwStatus = 0; - *pdwStatus = 0; - - // if createOutputSample actually make a copy of the sample, - // (for example, JPEG encoding case), we need to copy the - // attribute from m_spSample to spOutputIMFSample - m_spSample.Reset(); - return hr; -} - -///////////////////////////////////////////////////////////////////// -// -// The actual processing is here, required operation is demux -// Other operation is optional -// -HRESULT -CSocMft0:: -CreateOutputSample( - _Outptr_result_maybenull_ - IMFSample **ppSample -) -{ - HRESULT hr = S_OK; - - //Do nothing for now - if (!ppSample) - { - return E_POINTER; - } - - m_spSample.CopyTo(ppSample); - - return hr; -} -///////////////////////////////////////////////////////////////////// -// -// Flush the MFT. -// -STDMETHODIMP CSocMft0::OnFlush() -{ - // For this MFT, flushing just means releasing the input sample. - CAutoLock lock(&m_critSec); - m_spSample.Reset(); - return S_OK; -} - -///////////////////////////////////////////////////////////////////// -// -// Get the mediaType of selected stream. -// -STDMETHODIMP CSocMft0::GetMediaType( - _In_ DWORD dwStreamId, - _In_ DWORD dwTypeIndex, - _Outptr_result_maybenull_ IMFMediaType **ppType -) -{ - HRESULT hr = S_OK; - ComPtr spMediaType; - - if (!ppType) - { - return E_POINTER; - } - - if (dwStreamId != 0) - { - return MF_E_INVALIDSTREAMNUMBER; - } - - if (dwTypeIndex >= m_listOfMediaTypes.size()) - { - return MF_E_NO_MORE_TYPES; - } - - hr = MFCreateMediaType(spMediaType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - return hr; - } - - hr = m_listOfMediaTypes[dwTypeIndex]->CopyAllItems(spMediaType.Get()); - if (FAILED(hr)) - { - return hr; - } - - return spMediaType.CopyTo(ppType); -} - -///////////////////////////////////////////////////////////////////// -// -// Check if the media type is supported by MFT0. -// -STDMETHODIMP CSocMft0::IsMediaTypeSupported( - _In_ UINT uiStreamId, - _In_opt_ IMFMediaType *pIMFMediaType, - _Outptr_opt_result_maybenull_ IMFMediaType **ppIMFMediaTypeFull -) -{ - HRESULT hr = S_OK; - - if (!pIMFMediaType) - { - return E_POINTER; - } - - if (uiStreamId != 0) - { - return MF_E_INVALIDINDEX; - } - - BOOL bFound = FALSE; - - - for (UINT i = 0; i < m_listOfMediaTypes.size(); i++) - { - DWORD dwResult = 0; - hr = m_listOfMediaTypes[i]->IsEqual(pIMFMediaType, &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) - { - m_listOfMediaTypes[i].CopyTo(ppIMFMediaTypeFull); - } - break; - } - else if (FAILED(hr)) - { - return hr; - } - } - - if (bFound == FALSE) - { - return MF_E_INVALIDMEDIATYPE; - } - - return S_OK; -} - -///////////////////////////////////////////////////////////////////// -// -// Check if the media type is supported by MFT0. -// -_Success_(return == 0) -STDMETHODIMP CSocMft0::FindMediaIndex( - _In_ UINT uiStreamId, - _In_ IMFMediaType *pIMFMediaType, - _Out_ UINT *puiMediaIndex -) -{ - HRESULT hr = S_OK; - - if (!pIMFMediaType || !puiMediaIndex) - { - return E_INVALIDARG; - } - - if (uiStreamId != 0) - { - return MF_E_INVALIDINDEX; - } - - BOOL bFound = FALSE; - - for (UINT i = 0; i < m_listOfMediaTypes.size(); i++) - { - DWORD dwResult = 0; - hr = m_listOfMediaTypes[i]->IsEqual(pIMFMediaType, &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; - *puiMediaIndex = i; - break; - } - else if (FAILED(hr)) - { - return hr; - } - } - - if (bFound == FALSE) - { - return MF_E_INVALIDMEDIATYPE; - } - - return S_OK; -} - -///////////////////////////////////////////////////////////////////// -// -// Generate the supported input media type from device source media type -// -STDMETHODIMP CSocMft0::GenerateMFMediaTypeListFromDevice() -{ - HRESULT hr = S_OK; - - if (!m_spSourceTransform) - { - return MF_E_NOT_FOUND; - } - - m_listOfMediaTypes.clear(); - UINT iMediaType = 0; - while (SUCCEEDED(hr)) - { - ComPtr spMediaType; - hr = m_spSourceTransform->GetOutputAvailableType(m_uiSourceStreamId, iMediaType, spMediaType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - if (hr == MF_E_NO_MORE_TYPES) - { - hr = S_OK; - } - break; - } - - if (m_stStreamType == PINNAME_IMAGE || m_stStreamType == PINNAME_VIDEO_STILL) - { - GUID guidPhotoSubType = {}; - spMediaType->GetGUID(MF_MT_SUBTYPE, &guidPhotoSubType); - if (IsEqualGUID(guidPhotoSubType, MFVideoFormat_NV12)) - { - // Need to set MF_MT_VIDEO_NOMINAL_RANGE on NV12 or the pipeline ends up with a copy due to mismatched nominal range - hr = spMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255); - if (FAILED(hr)) - { - return hr; - } - } - - - m_listOfMediaTypes.push_back(spMediaType); - } - - else if (m_stStreamType == PINNAME_CAPTURE) - { - UINT32 width = 0; - UINT32 height = 0; - hr = MFGetAttributeSize(spMediaType.Get(), MF_MT_FRAME_SIZE, &width, &height); - if (FAILED(hr)) - { - return hr; - } - - MFVideoArea validVideo; - validVideo.OffsetX.value = 0; - validVideo.OffsetX.fract = 0; - validVideo.OffsetY.value = 0; - validVideo.OffsetY.fract = 0; - validVideo.Area.cx = width; - validVideo.Area.cy = height; - hr = spMediaType->SetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&validVideo, sizeof(validVideo)); - if (FAILED(hr)) - { - return hr; - } - - m_listOfMediaTypes.push_back(spMediaType); - } - - else - { - m_listOfMediaTypes.push_back(spMediaType); - } - - iMediaType++; - } - - return hr; -} - -///////////////////////////////////////////////////////////////////// -// -// Get the current media type in order to generate photo confirmation -// -HRESULT CSocMft0::GetPreviewMediaType( - _Outptr_result_maybenull_ IMFMediaType **ppType -) -{ - CAutoLock lock(&m_critSec); - if (!m_spSourceTransform) - { - return MF_E_NOT_FOUND; - } - - DWORD dwInStreamCount = 0, dwOutStreamCount = 0; - HRESULT hr = m_spSourceTransform->GetStreamCount( - &dwInStreamCount, - &dwOutStreamCount); - if (FAILED(hr)) - { - return hr; - } - - for (UINT32 i = 0; i < dwOutStreamCount; i++) - { - ComPtr spAttributes; - hr = m_spSourceTransform->GetOutputStreamAttributes(i, spAttributes.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - continue; - } - - GUID guidPinCategory = GUID_NULL; - hr = spAttributes->GetGUID( - MF_DEVICESTREAM_STREAM_CATEGORY, - &guidPinCategory); - if (FAILED(hr)) - { - continue; - } - if (IsEqualGUID(guidPinCategory, PINNAME_VIDEO_PREVIEW)) - { - ComPtr spMediaType; - hr = m_spSourceTransform->GetOutputCurrentType(i, spMediaType.ReleaseAndGetAddressOf()); - if (FAILED(hr)) - { - return MF_E_NOT_FOUND; - } - return spMediaType.CopyTo(ppType); - } - } - - return MF_E_NOT_FOUND; -} - -#if (NTDDI_VERSION >= NTDDI_WINBLUE) -///////////////////////////////////////////////////////////////////// -// -// Handle the Metadata with the buffer -// -HRESULT CSocMft0::ProcessMetadata() -{ - ComPtr spMetadata; - HRESULT hr = m_spSample->GetUnknown(MFSampleExtension_CaptureMetadata, IID_PPV_ARGS(spMetadata.ReleaseAndGetAddressOf())); - if (FAILED(hr)) - { - return hr; - } - - ComPtr 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(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 - (reinterpret_cast(pItem) + pItem->Size); - } - - if (lBufferLeft != 0) - { - //Check and log for malformated data - return E_UNEXPECTED; - } - - return S_OK; -} - -HRESULT CSocMft0::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 CSocMft0::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 -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 CSocMft0::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 CSocMft0::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 // (NTDDI_VERSION >= NTDDI_WINBLUE) -HRESULT CSocMft0::FillBufferLengthFromMediaType( - _In_ IMFMediaType *pPreviewType, - _Inout_ IMFMediaBuffer *pBuffer -) -{ - if (!pPreviewType || !pBuffer) - { - return E_INVALIDARG; - } - - UINT32 uiWidth = 0, uiHeight = 0, uiImageSize = 0; - GUID guidSubType = {}; - - HRESULT hr = MFGetAttributeSize(pPreviewType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight); - if (FAILED(hr)) - { - return hr; - } - - hr = pPreviewType->GetGUID(MF_MT_SUBTYPE, &guidSubType); - if (FAILED(hr)) - { - return hr; - } - - hr = MFCalculateImageSize(guidSubType, uiWidth, uiHeight, &uiImageSize); - if (FAILED(hr)) - { - return hr; - } - - return pBuffer->SetCurrentLength(uiImageSize); -} - -HRESULT CSocMft0::GetVideoStabilizationEnabled() -{ - HRESULT hr = S_OK; - ComPtr spKsControl; - KSPROPERTY ksProperty = { 0 }; - KSPROPERTY_CUSTOM_CAMERACONTROL_MFT0_VIDEOSTABILIZATION_S ksData = { 0 }; - ULONG bytesReturned = 0; - - if (m_spSourceTransform != NULL) - { - hr = m_spSourceTransform.As(&spKsControl); - if (SUCCEEDED(hr)) - { - ksProperty.Set = PROPSETID_VIDCAP_CUSTOM_CAMERACONTROL_MFT0; - ksProperty.Id = KSPROPERTY_CUSTOM_CAMERACONTROL_MFT0_VIDEOSTABILIZATION; - ksProperty.Flags = KSPROPERTY_TYPE_GET; - - hr = spKsControl->KsProperty(&ksProperty, sizeof(ksProperty), &ksData, sizeof(ksData), &bytesReturned); - if (SUCCEEDED(hr)) - { - m_bEnableVideoStabilization = ksData.VideoStabilizationEnabled; - } - } - } - else - { - hr = E_INVALIDARG; - } - return hr; -} diff --git a/avstream/avscamera/mft0/MFT0Impl.h b/avstream/avscamera/mft0/MFT0Impl.h deleted file mode 100644 index 9427dd7d4..000000000 --- a/avstream/avscamera/mft0/MFT0Impl.h +++ /dev/null @@ -1,316 +0,0 @@ -/************************************************************************** - - A/V Stream Camera Sample - - Copyright (c) 2013, Microsoft Corporation. - - File: - - Mft0Impl.h - - Abstract: - - The CSocMft0 class definition - an implementation of the iSocMft0 - interface found in Mft0.idl. - - History: - - created 4/26/2013 - -**************************************************************************/ - - -#pragma once -#include "Mft0.h" -#include "SampleHelpers.h" -#include "Mft0clsid.h" - -#include - -// CSocMft0 -#define FaceDetectionDelayMax 2 //frames between emitting facedetection data - -ULONG DllAddRef(); -ULONG DllRelease(); - -using namespace Microsoft::WRL; - -class CSocMft0: - public Microsoft::WRL::RuntimeClass, - ISocMft0, - IMFTransform, - IInspectable> -{ - -public: - - static HRESULT CreateInstance(REFIID iid, void **ppMFT); - - CSocMft0(): - m_bEnableEffects(TRUE), - m_bEnableVideoStabilization(FALSE), - m_uiSourceStreamId(0), - m_uiInternalState(0), - m_uThumbnailScaleFactor(4) - { - InitializeCriticalSection(&m_critSec); - m_stThumbnailFormat = MFVideoFormat_ARGB32; - DllAddRef(); - - } - - HRESULT FinalConstruct(); - -public: - - /*ISocMft0*/ - STDMETHOD(SetState)(UINT32 state); - STDMETHOD(GetState)(UINT32 *pState); - - /*IInspectable*/ - STDMETHOD(GetIids)( - _Out_ ULONG *iidCount, - _Outptr_result_buffer_maybenull_(*iidCount) - IID **iids - ); - - STDMETHOD(GetRuntimeClassName)( - _Outptr_result_maybenull_ HSTRING *pClassName - ); - - STDMETHOD(GetTrustLevel)( - _Out_ TrustLevel *trustLevel - ); - - /*IMFTransform*/ - STDMETHOD(GetStreamLimits)( - _Out_ DWORD *pdwInputMinimum, - _Out_ DWORD *pdwInputMaximum, - _Out_ DWORD *pdwOutputMinimum, - _Out_ DWORD *pdwOutputMaximum - ); - - STDMETHOD(GetStreamCount)( - _Out_ DWORD *pcInputStreams, - _Out_ DWORD *pcOutputStreams - ); - - STDMETHOD(GetStreamIDs)( - DWORD dwInputIDArraySize, - _Out_writes_(dwInputIDArraySize) DWORD *pdwInputIDs, - DWORD dwOutputIDArraySize, - _Out_writes_(dwOutputIDArraySize) DWORD *pdwOutputIDs - ); - - STDMETHOD(GetInputStreamInfo)( - DWORD dwInputStreamID, - _Out_ MFT_INPUT_STREAM_INFO *pStreamInfo - ); - - STDMETHOD(GetOutputStreamInfo)( - DWORD dwOutputStreamID, - _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo - ); - - STDMETHOD(GetAttributes)( - _Outptr_result_maybenull_ IMFAttributes **pAttributes - ); - - STDMETHOD(GetInputStreamAttributes)( - DWORD dwInputStreamID, - _Outptr_result_maybenull_ IMFAttributes **pAttributes - ); - - STDMETHOD(GetOutputStreamAttributes)( - DWORD dwOutputStreamID, - _Outptr_result_maybenull_ - IMFAttributes **pAttributes - ); - - STDMETHOD(DeleteInputStream)( - DWORD dwStreamID - ); - - STDMETHOD(AddInputStreams)( - DWORD cStreams, - _In_ DWORD *adwStreamIDs - ); - - STDMETHOD(GetInputAvailableType)( - DWORD dwInputStreamID, - DWORD dwTypeIndex, - _Outptr_result_maybenull_ IMFMediaType **ppType - ); - - STDMETHOD(GetOutputAvailableType)( - DWORD dwOutputStreamID, - DWORD dwTypeIndex, - _Outptr_result_maybenull_ IMFMediaType **ppType - ); - - STDMETHOD(SetInputType)( - DWORD dwInputStreamID, - _In_opt_ IMFMediaType *pType, - DWORD dwFlags); - - STDMETHOD(SetOutputType)( - DWORD dwOutputStreamID, - _In_opt_ IMFMediaType *pType, - DWORD dwFlags); - - STDMETHOD(GetInputCurrentType)( - DWORD dwInputStreamID, - _Outptr_result_maybenull_ IMFMediaType **ppType - ); - - STDMETHOD(GetOutputCurrentType)( - DWORD dwOutputStreamID, - _Outptr_result_maybenull_ IMFMediaType **ppType - ); - - STDMETHOD(GetInputStatus)( - DWORD dwInputStreamID, - _Out_ DWORD *pdwFlags - ); - - STDMETHOD(GetOutputStatus)( - _Out_ DWORD *pdwFlags - ); - - STDMETHOD(SetOutputBounds)( - LONGLONG hnsLowerBound, - LONGLONG hnsUpperBound - ); - - STDMETHOD(ProcessEvent)( - DWORD dwInputStreamID, - _In_opt_ IMFMediaEvent *pEvent - ); - - STDMETHOD(ProcessMessage)( - MFT_MESSAGE_TYPE eMessage, - ULONG_PTR ulParam - ); - - STDMETHOD(ProcessInput)( - DWORD dwInputStreamID, - IMFSample *pSample, - DWORD dwFlags - ); - - STDMETHOD(ProcessOutput)( - DWORD dwFlags, - DWORD cOutputBufferCount, - MFT_OUTPUT_DATA_BUFFER *pOutputSamples, - DWORD *pdwStatus - ); - -protected: - virtual ~CSocMft0() - { - DeleteCriticalSection(&m_critSec); - DllRelease(); - } - - STDMETHOD(GetMediaType)( - _In_ DWORD dwStreamID, - _In_ DWORD dwTypeIndex, - _Outptr_result_maybenull_ IMFMediaType **ppType - ); - - STDMETHOD(IsMediaTypeSupported)( - _In_ UINT uiStreamId, - _In_opt_ IMFMediaType *pIMFMediaType, - _Outptr_opt_result_maybenull_ IMFMediaType **ppIMFMediaTypeFull = NULL - ); - - STDMETHOD(GenerateMFMediaTypeListFromDevice)(); - - _Success_(return == 0) - STDMETHOD(FindMediaIndex)( - _In_ UINT uiStreamId, - _In_ IMFMediaType *pIMFMediaType, - _Out_ UINT *puiMediaIndex - ); - - // HasPendingOutput: Returns TRUE if the MFT is holding an input sample. - BOOL HasPendingOutput() const - { - return m_spSample != NULL; - } - - HRESULT CreateOutputSample( - _Outptr_result_maybenull_ IMFSample **ppSample - ); - - HRESULT GetPreviewMediaType( - _Outptr_result_maybenull_ IMFMediaType **ppType - ); -#if (NTDDI_VERSION >= NTDDI_WINBLUE) - HRESULT ProcessMetadata(); - - 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 ParseMetadata_FaceDetection( - _In_ PKSCAMERA_METADATA_ITEMHEADER pItem, - _In_ IMFAttributes *pMetaDataAttributes - ); -#endif // (NTDDI_VERSION >= NTDDI_WINBLUE) - HRESULT FillBufferLengthFromMediaType( - _In_ IMFMediaType *pPreviewType, - _Inout_ IMFMediaBuffer *pBuffer - ); - - STDMETHOD(OnFlush)(); - - HRESULT GetVideoStabilizationEnabled(); - - HRESULT GetThumbnailResolution(); - - HRESULT OnProcessImage( - _Outptr_result_maybenull_ - IMFSample **ppIMFOutputSample - ); - - CRITICAL_SECTION m_critSec; - - ComPtr m_spSample; // Input sample. - ComPtr m_spInputType; // Input media type. - ComPtr m_spOutputType; // Output media type. - - // Image transform function. (Changes based on the media type.) - ComPtr m_spInputAttributes; - ComPtr m_spGlobalAttributes; - GUID m_stStreamType; - ComPtr m_spSourceTransform; - volatile BOOL m_bEnableEffects; - BOOL m_bEnableVideoStabilization; - UINT m_uiSourceStreamId; - UINT m_uiInternalState; - BYTE m_uThumbnailScaleFactor; - GUID m_stThumbnailFormat; - - std::vector> - m_listOfMediaTypes; - -}; - -inline HRESULT MFT0CreateInstance(REFIID riid, void **ppv) -{ - return CSocMft0::CreateInstance(riid, ppv); -} - -//CoCreateableClass(CSocMft0); \ No newline at end of file diff --git a/avstream/avscamera/mft0/MFT0clsid.h b/avstream/avscamera/mft0/MFT0clsid.h deleted file mode 100644 index d8aad5f5c..000000000 --- a/avstream/avscamera/mft0/MFT0clsid.h +++ /dev/null @@ -1,26 +0,0 @@ -/************************************************************************** - - A/V Stream Camera Sample - - Copyright (c) 2015, Microsoft Corporation. - - File: - - Mft0clsid.h - - Abstract: - - Define the Class GUID of the MFT. - - History: - - created 2/19/2015 - -**************************************************************************/ - -#pragma once - -// CLSID of the MFT. -// {1C2CE17A-FAAD-4E73-85E7-167068093F25} -DEFINE_GUID(CLSID_AvsCamMft0, - 0x1c2ce17a, 0xfaad, 0x4e73, 0x85, 0xe7, 0x16, 0x70, 0x68, 0x9, 0x3f, 0x25); diff --git a/avstream/avscamera/mft0/SampleHelpers.h b/avstream/avscamera/mft0/SampleHelpers.h deleted file mode 100644 index 11908f829..000000000 --- a/avstream/avscamera/mft0/SampleHelpers.h +++ /dev/null @@ -1,106 +0,0 @@ -/************************************************************************** - - A/V Stream Camera Sample - - Copyright (c) 2013, Microsoft Corporation. - - File: - - SampleHelpers.h - - Abstract: - - Helper classes for the MFT0. - - History: - - created 4/26/2013 - -**************************************************************************/ - -#pragma once - -/***************************************************************************\ -***************************************************************************** -* -* class CAutoLock -* -* Locks a critical section at construction time and unlocks it automatically -* when the object goes out of scope -* -***************************************************************************** -\***************************************************************************/ - -class CAutoLock -{ -private: - // Make copy constructor and assignment operator inaccessible - CAutoLock(const CAutoLock &refAutoLock); - CAutoLock &operator=(const CAutoLock &refAutoLock); - - // CAutoLock should not be created on the heap, so declare - // (but do not implement) private operator new/delete. - static void *operator new(size_t); - static void operator delete(void *); - static void *operator new[](size_t); - static void operator delete[](void *); - -protected: - CRITICAL_SECTION *m_pLock; - -public: - _Acquires_lock_(m_pLock) - explicit CAutoLock(CRITICAL_SECTION *pLock): - m_pLock(pLock) - { - EnterCriticalSection(m_pLock); - } - - _Releases_lock_(m_pLock) - ~CAutoLock() - { - LeaveCriticalSection(m_pLock); - } -}; - -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 m_spBuffer; - bool m_bLocked; -}; diff --git a/avstream/avscamera/mft0/dllmain.cpp b/avstream/avscamera/mft0/dllmain.cpp deleted file mode 100644 index b57464177..000000000 --- a/avstream/avscamera/mft0/dllmain.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/************************************************************************** - - A/V Stream Camera Sample - - Copyright (c) 2014, Microsoft Corporation. - - File: - - dllmain.cpp - - Abstract: - - DLL and COM initialization. - - History: - - created 5/15/2014 - -**************************************************************************/ -//// 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 - - -#include "stdafx.h" -#include "Mft0.h" -#include "Mft0clsid.h" -#include "Mft0Impl.h" -#include - -using namespace Microsoft::WRL; - -// Module Ref count -volatile ULONG g_cRefModule = 0; - -// Handle to the DLL's module -HMODULE g_hModule = NULL; - -ULONG DllAddRef() -{ - return InterlockedIncrement(&g_cRefModule); -} - -ULONG DllRelease() -{ - return InterlockedDecrement(&g_cRefModule); -} - -class CClassFactory : public IClassFactory -{ -public: - static HRESULT CreateInstance( - REFCLSID clsid, - REFIID riid, - _COM_Outptr_ void **ppv - ) - { - *ppv = NULL; - - HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; - - if(IsEqualGUID(clsid, CLSID_AvsCamMft0)) - { - IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(); - if(!pClassFactory) - { - return E_OUTOFMEMORY; - } - hr = pClassFactory->QueryInterface(riid, ppv); - pClassFactory->Release(); - } - return hr; - } - - //IUnknown methods - IFACEMETHODIMP QueryInterface(REFIID riid, void **ppvObject) - { - HRESULT hr = S_OK; - - if(ppvObject == NULL) - { - return E_POINTER; - } - - if(riid == IID_IUnknown) - { - *ppvObject = (IUnknown*)this; - } - else if(riid == IID_IClassFactory) - { - *ppvObject = (IClassFactory*)this; - } - else - { - *ppvObject = NULL; - return E_NOINTERFACE; - } - - AddRef(); - - return hr; - } - - 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(_In_ IUnknown *punkOuter, _In_ REFIID riid, _Outptr_ void **ppv) - { - return punkOuter ? CLASS_E_NOAGGREGATION : MFT0CreateInstance(riid, ppv); - } - - IFACEMETHODIMP LockServer(BOOL fLock) - { - if(fLock) - { - DllAddRef(); - } - else - { - DllRelease(); - } - return S_OK; - } - -private: - CClassFactory() : - m_cRef(1) - { - DllAddRef(); - } - - ~CClassFactory() - { - DllRelease(); - } - - long m_cRef; -}; - - - - -STDAPI_(BOOL) DllMain(_In_ HINSTANCE hinst, DWORD reason, _In_opt_ void *) -{ - if (reason == DLL_PROCESS_ATTACH) - { - g_hModule = (HMODULE)hinst; - DisableThreadLibraryCalls(hinst); - } - return TRUE; -} - -// -// DllCanUnloadNow -// -///////////////////////////////////////////////////////////////////////// -__control_entrypoint(DllExport) -STDAPI DllCanUnloadNow() -{ - return (g_cRefModule == 0) ? S_OK : S_FALSE; -} - -///////////////////////////////////////////////////////////////////////// -// -// DllGetClassObject -// -///////////////////////////////////////////////////////////////////////// -_Check_return_ -STDAPI DllGetClassObject( - _In_ REFCLSID rclsid, - _In_ REFIID riid, - _Outptr_ LPVOID FAR *ppv -) -{ - return CClassFactory::CreateInstance(rclsid, riid, ppv); -} diff --git a/avstream/avscamera/mft0/stdafx.h b/avstream/avscamera/mft0/stdafx.h deleted file mode 100644 index 6d784805c..000000000 --- a/avstream/avscamera/mft0/stdafx.h +++ /dev/null @@ -1,39 +0,0 @@ -//// 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 - -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, -// but are changed infrequently - -#pragma once - -#ifndef STRICT -#define STRICT -#endif - -#include "targetver.h" -#if (NTDDI_VERSION >= NTDDI_WIN10_VB) -#pragma message("MFT0 is deprecated for this target Windows version and beyond- Change project settings to target an older version of Windows") -#endif - -#if (NTDDI_VERSION <= NTDDI_WIN7) -// TODO: disable the MFT0 conditional to the target system version -#pragma message("MFT0 is in not supported in this target Windows version - Change project settings to target a newer version of Windows") -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace Microsoft::WRL; \ No newline at end of file diff --git a/avstream/avscamera/mft0/stdafxsrc.cpp b/avstream/avscamera/mft0/stdafxsrc.cpp deleted file mode 100644 index 1577c4e3b..000000000 --- a/avstream/avscamera/mft0/stdafxsrc.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "stdafx.h" \ No newline at end of file diff --git a/avstream/avscamera/mft0/targetver.h b/avstream/avscamera/mft0/targetver.h deleted file mode 100644 index fc349fa5f..000000000 --- a/avstream/avscamera/mft0/targetver.h +++ /dev/null @@ -1,15 +0,0 @@ -//// 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 - -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include diff --git a/avstream/avscamera/sys/avscamera.inx b/avstream/avscamera/sys/avscamera.inx index e68a29c4d..f75da695e 100644 Binary files a/avstream/avscamera/sys/avscamera.inx and b/avstream/avscamera/sys/avscamera.inx differ diff --git a/avstream/sampledevicemft/SampleSocDeviceMFT.cpp b/avstream/sampledevicemft/SampleSocDeviceMFT.cpp new file mode 100644 index 000000000..2a91906f8 --- /dev/null +++ b/avstream/sampledevicemft/SampleSocDeviceMFT.cpp @@ -0,0 +1,1533 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" +#include "multipinmft.h" +#ifdef MF_WPP +#include "multipinmft.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif +// +// Note since MFT_UNIQUE_METHOD_NAMES is defined all the functions of IMFTransform have the Mft suffix.. +// +extern const CLSID CLSID_HwMFTActivate; + +CMultipinMft::CMultipinMft() +: m_nRefCount( 0 ), + m_InputPinCount( 0 ), + m_OutputPinCount( 0 ), + m_dwWorkQueueId ( MFASYNC_CALLBACK_QUEUE_MULTITHREADED ), + m_lWorkQueuePriority ( 0 ), + m_spAttributes( nullptr ), + m_spSourceTransform( nullptr ), + m_SymbolicLink(nullptr) +{ + HRESULT hr = S_OK; + ComPtr pAttributes = nullptr; + MFCreateAttributes( &pAttributes, 0 ); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE ),done); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ),done); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE ), done); + DMFTCHECKHR_GOTO(pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" ),done); + m_spAttributes = pAttributes; +done: + if (FAILED(hr)) + { + + } +} + +CMultipinMft::~CMultipinMft( ) +{ + + + for ( ULONG ulIndex = 0, ulSize = (ULONG) m_InPins.size(); ulIndex < ulSize; ulIndex++ ) + { + SAFERELEASE(m_InPins[ ulIndex ]); + } + m_InPins.clear(); + for (ULONG ulIndex = 0, ulSize = (ULONG) m_OutPins.size(); ulIndex < ulSize; ulIndex++) + { + SAFERELEASE(m_OutPins[ ulIndex ]); + } + m_OutPins.clear(); + SAFE_ARRAYDELETE(m_SymbolicLink); + m_spSourceTransform = nullptr; + +} + +STDMETHODIMP_(ULONG) CMultipinMft::AddRef( + void + ) +{ + return InterlockedIncrement(&m_nRefCount); +} + +STDMETHODIMP_(ULONG) CMultipinMft::Release( + void + ) +{ + ULONG uCount = InterlockedDecrement(&m_nRefCount); + + if ( uCount == 0 ) + { + delete this; + } + return uCount; +} + +STDMETHODIMP CMultipinMft::QueryInterface( + _In_ REFIID iid, + _COM_Outptr_ void** ppv + ) +{ + + HRESULT hr = S_OK; + *ppv = NULL; + + if ((iid == __uuidof(IMFDeviceTransform)) || (iid == __uuidof(IUnknown))) + { + *ppv = static_cast< IMFDeviceTransform* >(this); + } + else if ( iid == __uuidof( IMFMediaEventGenerator ) ) + { + *ppv = static_cast< IMFMediaEventGenerator* >(this); + } + else if ( iid == __uuidof( IMFShutdown ) ) + { + *ppv = static_cast< IMFShutdown* >( this ); + } +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + else if (iid == __uuidof(IMFTransform)) + { + *ppv = static_cast< IMFTransform* >(this); + } +#endif + else if ( iid == __uuidof( IKsControl ) ) + { + *ppv = static_cast< IKsControl* >( this ); + } + else if ( iid == __uuidof( IMFRealTimeClientEx ) ) + { + *ppv = static_cast< IMFRealTimeClientEx* >( this ); + } + +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + else if (iid == __uuidof(IMFSampleAllocatorControl)) + { + *ppv = static_cast(this); + } +#endif + else + { + hr = E_NOINTERFACE; + goto done; + } + AddRef(); +done: + return hr; +} + +/*++ + Description: + This function is the entry point of the transform + The following things may be initialized here + 1) Query for MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL on the attributes supplied + 2) From the IUnknown acquired get the IMFTransform interface. + 3) Get the stream count.. The output streams are of consequence to the tranform. + The input streams should correspond to the output streams exposed by the source transform + acquired from the Attributes supplied. + 4) Get the IKSControl which is used to send KSPROPERTIES, KSEVENTS and KSMETHODS to the driver for the filer level. Store it in your filter class + 5) Get the OutPutStreamAttributes for the output pins of the source transform. This can further be used to QI and acquire + the IKSControl related to the specific pin. This can be used to send PIN level KSPROPERTIES, EVENTS and METHODS to the pins + 6) Create the output pins + +--*/ + +// This sample will create a grayscale for known media types. Please remove MF_DEVICEMFT_ADD_GRAYSCALER_ to remove the grayscaler +// This sample also has photo confirmation enabled remove DMF_DEVICEMFT_PHTOTOCONFIRMATION to remove photo confirmation +// Please search for the @@@@ README tag for critical sections in code and it's documentation +// +STDMETHODIMP CMultipinMft::InitializeTransform ( + _In_ IMFAttributes *pAttributes + ) +{ + HRESULT hr = S_OK; + ComPtr spFilterUnk = nullptr; + DWORD *pcInputStreams = NULL, *pcOutputStreams = NULL; + DWORD inputStreams = 0; + DWORD outputStreams = 0; + GUID* outGuids = NULL; + GUID streamCategory = GUID_NULL; + ULONG ulOutPinIndex = 0; + UINT32 uiSymLinkLen = 0; + CPinCreationFactory* pPinFactory = new (std::nothrow) CPinCreationFactory(this); + DMFTCHECKNULL_GOTO( pAttributes, done, E_INVALIDARG ); + // + // The attribute passed with MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL is the source transform. This generally represents a filter + // This needs to be stored so that we know the device properties. We cache it. We query for the IKSControl which is used to send + // controls to the driver. + // + DMFTCHECKHR_GOTO( pAttributes->GetUnknown( MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL,IID_PPV_ARGS( &spFilterUnk ) ),done ); + + if (SUCCEEDED(pAttributes->GetStringLength(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &uiSymLinkLen))) // Not available prior to RS5 + { + m_SymbolicLink = new (std::nothrow) WCHAR[++uiSymLinkLen]; + DMFTCHECKNULL_GOTO(m_SymbolicLink, done, E_OUTOFMEMORY); + DMFTCHECKHR_GOTO(pAttributes->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, m_SymbolicLink, uiSymLinkLen, &uiSymLinkLen), done); + } + + DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done ); + + DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done ); + + DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamCount( &inputStreams, &outputStreams ), done ); + + spFilterUnk = nullptr; + + // + //The number of input pins created by the device transform should match the pins exposed by + //the source transform i.e. outputStreams from SourceTransform or DevProxy = Input pins of the Device MFT + // + + if ( inputStreams > 0 || outputStreams > 0 ) + { + pcInputStreams = new (std::nothrow) DWORD[ inputStreams ]; + DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY); + + pcOutputStreams = new (std::nothrow) DWORD[ outputStreams ]; + DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY ); + + DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamIDs( inputStreams, pcInputStreams, + outputStreams, + pcOutputStreams ),done ); + + // + // Output pins from DevProxy = Input pins of device MFT.. We are the first transform in the pipeline before MFT0 + // + + for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ ) + { + ComPtr pInAttributes = nullptr; + BOOL bCustom = FALSE; + ComPtr spInPin; + + DMFTCHECKHR_GOTO(pPinFactory->CreatePin( + pcOutputStreams[ulIndex], /*Input Pin ID as advertised by the pipeline*/ + 0, /*This is not needed for Input Pin*/ + CPinCreationFactory::DMFT_PIN_INPUT, /*Input Pin*/ + (CBasePin**)spInPin.GetAddressOf(), + bCustom), done); + if (bCustom) + { + m_CustomPinCount++; + } + hr = ExceptionBoundary([&]() + { + m_InPins.push_back(spInPin.Get()); + }); + DMFTCHECKHR_GOTO(hr, done); + DMFTCHECKHR_GOTO( spInPin->Init(m_spSourceTransform.Get() ), done); + spInPin.Detach(); + } + + // + // Create one on one mapping + // + for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++) + { + + ComPtr spoPin; + BOOL bCustom = FALSE; + ComPtr spiPin = ( CInPin * )m_InPins[ ulIndex ]; + + if (spiPin.Get()) + { + BOOL isCustom = false; + if (SUCCEEDED(CheckCustomPin(spiPin.Get(), &isCustom)) && (isCustom)) + { + // + // In this sample we are not connecting the custom pin to the output + // This is because we really have no way of testing the custom pin with the + // pipeline. + // This however can be changed if the custom media type is converted here in + // the device MFT and later exposed to the pipeline.. + // + continue; + } + + DMFTCHECKHR_GOTO(pPinFactory->CreatePin(spiPin->streamId(), /*Input Pin connected to the Output Pin*/ + ulOutPinIndex, /*Output pin Id*/ + CPinCreationFactory::DMFT_PIN_OUTPUT, /*Output pin */ + (CBasePin**)spoPin.ReleaseAndGetAddressOf(), + bCustom), done); + hr = BridgeInputPinOutputPin(spiPin.Get(), spoPin.Get()); + if (SUCCEEDED(hr)) + { + DMFTCHECKHR_GOTO(ExceptionBoundary([&]() + { + m_OutPins.push_back(spoPin.Get()); + }), done); + spoPin.Detach(); + ulOutPinIndex++; + hr = S_OK; + } + if (hr == MF_E_INVALID_STREAM_DATA) + { + // Skip the pin which doesn't have any mediatypes exposed + hr = S_OK; + } + DMFTCHECKHR_GOTO(hr, done); + } + } + + } + + m_InputPinCount = ULONG ( m_InPins.size() ); + m_OutputPinCount = ULONG ( m_OutPins.size() ); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!",hr,hr); + + if ( pcInputStreams ) + { + delete[ ] ( pcInputStreams ); + } + if ( pcOutputStreams ) + { + delete[ ] ( pcOutputStreams ); + } + if ( outGuids ) + { + delete [] ( outGuids ); + } + SAFE_DELETE(pPinFactory); + if ( FAILED( hr ) ) + { + //Release the pins and the resources acquired + for (ULONG ulIndex = 0, ulSize = (ULONG)m_InPins.size(); ulIndex < ulSize; ulIndex++) + { + SAFERELEASE(m_InPins[ulIndex]); + } + m_InPins.clear(); + for (ULONG ulIndex = 0, ulSize = (ULONG)m_OutPins.size(); ulIndex < ulSize; ulIndex++) + { + SAFERELEASE(m_OutPins[ulIndex]); + } + m_OutPins.clear(); + // + // Simply clear the custom pins since the input pins must have deleted the pin + // + m_spSourceTransform = nullptr; + m_spIkscontrol = nullptr; + } + return hr; +} + + +STDMETHODIMP CMultipinMft::SetWorkQueueEx( + _In_ DWORD dwWorkQueueId, + _In_ LONG lWorkItemBasePriority + ) +/*++ + Description: + + Implements IMFRealTimeClientEx::SetWorkQueueEx function + +--*/ +{ + CAutoLock lock( m_critSec ); + // + // Cache the WorkQueuId and WorkItemBasePriority. This is called once soon after the device MFT is initialized + // + m_dwWorkQueueId = dwWorkQueueId; + m_lWorkQueuePriority = lWorkItemBasePriority; + // Set it on the pins + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++) + { + m_InPins[dwIndex]->SetWorkQueue(dwWorkQueueId); + } + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++) + { + m_OutPins[dwIndex]->SetWorkQueue(dwWorkQueueId); + } + return S_OK; + +} + +// +// IMFDeviceTransform functions +// +STDMETHODIMP CMultipinMft::GetStreamCount( + _Inout_ DWORD *pdwInputStreams, + _Inout_ DWORD *pdwOutputStreams + ) +/*++ + Description: Implements IMFTransform::GetStreamCount function +--*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + DMFTCHECKNULL_GOTO(pdwInputStreams, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pdwOutputStreams, done, E_INVALIDARG); + *pdwInputStreams = m_InputPinCount; + *pdwOutputStreams = m_OutputPinCount; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); +done: + return hr; +} + +// +//Doesn't strictly conform to the GetStreamIDs on IMFTransform Interface! +// +STDMETHODIMP CMultipinMft::GetStreamIDs( + _In_ DWORD dwInputIDArraySize, + _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs, + _In_ DWORD dwOutputIDArraySize, + _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)), + _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs + ) +/*++ + Description: + Implements IMFTransform::GetStreamIDs function +--*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + if ( ( dwInputIDArraySize < m_InputPinCount ) && ( dwOutputIDArraySize < m_OutputPinCount ) ) + { + hr = MF_E_BUFFERTOOSMALL; + goto done; + } + + if ( dwInputIDArraySize ) + { + DMFTCHECKNULL_GOTO( pdwInputIDs, done, E_POINTER ); + for ( DWORD dwIndex = 0; dwIndex < ((dwInputIDArraySize > m_InputPinCount) ? m_InputPinCount: + dwInputIDArraySize); dwIndex++ ) + { + pdwInputIDs[ dwIndex ] = ( m_InPins[dwIndex] )->streamId(); + } + } + + if ( dwOutputIDArraySize ) + { + DMFTCHECKNULL_GOTO( pdwOutputIDs, done, E_POINTER ); + for ( DWORD dwIndex = 0; dwIndex < ((dwOutputIDArraySize > m_OutputPinCount)? m_OutputPinCount: + dwOutputIDArraySize); dwIndex++ ) + { + pdwOutputIDs[ dwIndex ] = (m_OutPins[ dwIndex ])->streamId(); + } + } +done: + return hr; +} + +/*++ +Name: CMultipinMft::GetInputAvailableType +Description: +Implements IMFTransform::GetInputAvailableType function. This function +gets the media type supported by the specified stream based on the +index dwTypeIndex. +--*/ +STDMETHODIMP CMultipinMft::GetInputAvailableType( + _In_ DWORD dwInputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType + ) +{ + HRESULT hr = S_OK; + + ComPtr spiPin = GetInPin( dwInputStreamID ); + DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO( spiPin, done, MF_E_INVALIDSTREAMNUMBER ); + + *ppMediaType = nullptr; + + hr = spiPin->GetOutputAvailableType( dwTypeIndex,ppMediaType ); + + if (FAILED(hr)) + { + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!", + dwInputStreamID, + dwTypeIndex, + hr); + } + +done: + return hr; +} + +STDMETHODIMP CMultipinMft::GetOutputAvailableType( + _In_ DWORD dwOutputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType + ) +/*++ + Description: + + Implements IMFTransform::GetOutputAvailableType function. This function + gets the media type supported by the specified stream based on the + index dwTypeIndex. + +--*/ +{ + HRESULT hr = S_OK; + CAutoLock Lock(m_critSec); + + ComPtr spoPin = GetOutPin( dwOutputStreamID ); + + DMFTCHECKNULL_GOTO( spoPin.Get(), done, MF_E_INVALIDSTREAMNUMBER ); + DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG); + + *ppMediaType = nullptr; + + hr = spoPin->GetOutputAvailableType( dwTypeIndex, ppMediaType ); + + if ( FAILED( hr ) ) + { + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!", + dwOutputStreamID, + dwTypeIndex, + hr ); + } + +done: + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputCurrentType( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType + ) +/*++ + Description: + Implements IMFTransform::GetInputCurrentType function. This function + returns the current media type set on the specified stream. +--*/ +{ + // + // The input current types will not come to this transform. + // The outputs of this transform matter. The DTM manages the + // output of this transform and the inptuts of the source transform + // + UNREFERENCED_PARAMETER(dwInputStreamID); + UNREFERENCED_PARAMETER(ppMediaType); + return S_OK; +} + +STDMETHODIMP CMultipinMft::GetOutputCurrentType( + _In_ DWORD dwOutputStreamID, + _Out_ IMFMediaType** ppMediaType + ) +/*++ + Description: + + Implements IMFTransform::GetOutputCurrentType function. This function + returns the current media type set on the specified stream. + +--*/ +{ + HRESULT hr = S_OK; + ComPtr spoPin; + CAutoLock lock( m_critSec ); + + DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG ); + + *ppMediaType = nullptr; + + spoPin = GetOutPin( dwOutputStreamID ); + + DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER ); + + DMFTCHECKHR_GOTO(spoPin->getMediaType( ppMediaType ),done ); + + DMFTCHECKNULL_GOTO( *ppMediaType, done, MF_E_TRANSFORM_TYPE_NOT_SET ); + +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + + +STDMETHODIMP CMultipinMft::ProcessEvent( + _In_ DWORD dwInputStreamID, + _In_ IMFMediaEvent* pEvent + ) + /*++ + Description: + + Implements IMFTransform::ProcessEvent function. This function + processes events that come to the MFT. + + --*/ +{ + UNREFERENCED_PARAMETER(dwInputStreamID); + UNREFERENCED_PARAMETER(pEvent); + return S_OK; +} + + + +STDMETHODIMP CMultipinMft::ProcessMessage( + _In_ MFT_MESSAGE_TYPE eMessage, + _In_ ULONG_PTR ulParam + ) +/*++ + Description: + + Implements IMFTransform::ProcessMessage function. This function + processes messages coming to the MFT. + +--*/ +{ + HRESULT hr = S_OK; + + UNREFERENCED_PARAMETER(ulParam); + + CAutoLock _lock( m_critSec ); + + printMessageEvent( eMessage ); + + switch ( eMessage ) + { + case MFT_MESSAGE_COMMAND_FLUSH: + // + // This is MFT wide flush.. Flush all output pins + // + (VOID)FlushAllStreams(); + break; + case MFT_MESSAGE_COMMAND_DRAIN: + // + // There is no draining for Device MFT. Just kept here for reference + // + break; + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + // + // No op for device MFTs + // + break; + case MFT_MESSAGE_SET_D3D_MANAGER: + { + if ( ulParam ) + { + ComPtr< IDirect3DDeviceManager9 > spD3D9Manager; + ComPtr< IMFDXGIDeviceManager > spDXGIManager; + + hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spD3D9Manager ) ); + if ( SUCCEEDED( hr ) ) + { + m_spDeviceManagerUnk = ( IUnknown* )ulParam; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IDirect3DDeviceManager9 %p, is passed", spD3D9Manager.Get() ); + } + else + { + hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spDXGIManager ) ); + if ( SUCCEEDED(hr) ) + { + m_spDeviceManagerUnk = (IUnknown*)ulParam; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IMFDXGIDeviceManager %p, is passed", spDXGIManager.Get()); + } + } + } + else + { + m_spDeviceManagerUnk = nullptr; + hr = S_OK; + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC!IDirect3DDeviceManager9 was not passed in"); + } + // + // set it on the pins. Can happen anytime + // + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++) + { + m_InPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get()); + } + for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++) + { + m_OutPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get()); + } + } + break; + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + { + SetStreamingState( DeviceStreamState_Run ); + } + break; + case MFT_MESSAGE_NOTIFY_END_STREAMING: + { + SetStreamingState(DeviceStreamState_Stop); + } + break; + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + { + SetStreamingState(DeviceStreamState_Stop); + } + break; + default: + ; + } + + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + return hr; +} + +STDMETHODIMP CMultipinMft::ProcessInput( + _In_ DWORD dwInputStreamID, + _In_ IMFSample* pSample, + _In_ DWORD dwFlags + ) +/*++ + Description: + + Implements IMFTransform::ProcessInput function.This function is called + when the sourcetransform has input to feed. the pins will try to deliver the + samples to the active output pins conencted. if none are connected then just + returns the sample back to the source transform + +--*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER( dwFlags ); + + ComPtr spInPin = GetInPin( dwInputStreamID ); + DMFTCHECKNULL_GOTO(spInPin, done, MF_E_INVALIDSTREAMNUMBER); + + if ( !IsStreaming() ) + { + goto done; + } + + DMFTCHECKHR_GOTO(spInPin->SendSample( pSample ), done ); +done: + DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); + // + //@@@@ README : There is a bug in the sample that the device transform manager which manages the + // device MFT does not release the sample after passing it to Device MFT in processInput like it should. The + // Device MFT therefore unfortunately has to make sure that the sample that leaves processoutput has a reference count of 1 + // + SAFE_RELEASE(pSample); + return hr; + +} + +STDMETHODIMP CMultipinMft::ProcessOutput( + _In_ DWORD dwFlags, + _In_ DWORD cOutputBufferCount, + _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, + _Out_ DWORD *pdwStatus +) +/*++ +Description: + +Implements IMFTransform::ProcessOutput function. This is called by the DTM when +the DT indicates it has samples to give. The DTM will send enough MFT_OUTPUT_DATA_BUFFER +pointers to be filled up as is the number of output pins available. The DT should traverse its +output pins and populate the corresponding MFT_OUTPUT_DATA_BUFFER with the samples available + +--*/ +{ + HRESULT hr = S_OK; + BOOL gotOne = false; + ComPtr spOpin; + UNREFERENCED_PARAMETER( dwFlags ); + + if (cOutputBufferCount > m_OutputPinCount ) + { + DMFTCHECKHR_GOTO( E_INVALIDARG, done ); + } + *pdwStatus = 0; + + for ( DWORD i = 0; i < cOutputBufferCount; i++ ) + { + DWORD dwStreamID = pOutputSamples[i].dwStreamID; + { + CAutoLock _lock(m_critSec); + spOpin = nullptr; + spOpin = GetOutPin(dwStreamID); + GUID pinGuid = GUID_NULL; + DMFTCHECKNULL_GOTO(spOpin.Get(), done, E_INVALIDARG); + } + if ( SUCCEEDED(spOpin->ProcessOutput( dwFlags, &pOutputSamples[i], + pdwStatus ) ) ) + { + gotOne = true; + } + } + if (gotOne) + { + hr = S_OK; + } + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputStreamAttributes( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes + ) +/*++ + Description: + + Implements IMFTransform::GetInputStreamAttributes function. This function + gets the specified input stream's attributes. + +--*/ +{ + HRESULT hr = S_OK; + ComPtr spIPin; + + DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG ); + *ppAttributes = nullptr; + + spIPin = GetInPin( dwInputStreamID ); + + DMFTCHECKNULL_GOTO(spIPin, done, E_INVALIDARG ); + + hr = spIPin->getPinAttributes(ppAttributes); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetOutputStreamAttributes( + _In_ DWORD dwOutputStreamID, + _Out_ IMFAttributes** ppAttributes + ) +/*++ + Description: + + Implements IMFTransform::GetOutputStreamAttributes function. This function + gets the specified output stream's attributes. + +--*/ +{ + HRESULT hr = S_OK; + ComPtr spoPin; + + DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG); + + *ppAttributes = nullptr; + + spoPin = GetOutPin(dwOutputStreamID); + + DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG ); + + DMFTCHECKHR_GOTO(spoPin->getPinAttributes(ppAttributes), done ); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +_Requires_no_locks_held_ +STDMETHODIMP CMultipinMft::SetInputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::SetInputStreamState function. + Sets the input stream state. + + The control lock is not taken here. The lock is taken for operations on + output pins. This operation is a result of the DT notifying the DTM that + output pin change has resulted in the need for the input to be changed. In + this case the DTM sends a getpreferredinputstate and then this call + + --*/ +{ + HRESULT hr = S_OK; + CAutoLock Lock(m_critSec); + ComPtr spiPin = GetInPin(dwStreamID); + DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER); + + DMFTCHECKHR_GOTO(spiPin->SetInputStreamState(pMediaType, value, dwFlags),done); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value + ) +{ + HRESULT hr = S_OK; + ComPtr piPin = GetInPin(dwStreamID); + + DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER); + + *value = piPin->GetState(); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +STDMETHODIMP CMultipinMft::SetOutputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState state, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::SetOutputStreamState function. + Sets the output stream state. This is called whenever the stream + is selected or deslected i.e. started or stopped. + + The control lock taken here and this operation should be atomic. + This function should check the input pins connected to the output pin + switch off the state of the input pin. Check if any other Pin connected + to the input pin is in a conflicting state with the state requested on this + output pin. Accordinly it calculates the media type to be set on the input pin + and the state to transition into. It then might recreate the other output pins + connected to it + --*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwFlags); + CAutoLock Lock(m_critSec); + + DMFTCHECKHR_GOTO(ChangeMediaTypeEx(dwStreamID, pMediaType, state),done); + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetOutputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *pState + ) + /*++ + Description: + + Implements IMFdeviceTransform::GetOutputStreamState function. + Gets the output stream state. + Called by the DTM to checks states. Atomic operation. needs a lock + --*/ +{ + HRESULT hr = S_OK; + CAutoLock lock(m_critSec); + + ComPtr spoPin = GetOutPin(dwStreamID); + DMFTCHECKNULL_GOTO(pState, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER); + *pState = spoPin->GetState(); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::GetInputStreamPreferredState( + _In_ DWORD dwStreamID, + _Inout_ DeviceStreamState *value, + _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType + ) + /*++ + Description: + + Implements IMFdeviceTransform::GetInputStreamPreferredState function. + Gets the preferred state and the media type to be set on the input pin. + The lock is not held as this will always be called only when we notify + DTM to call us. We notify DTM only from the context on operations + happening on the output pin + --*/ +{ + HRESULT hr = S_OK; + ComPtr spiPin = GetInPin(dwStreamID); + DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER); + hr = spiPin->GetInputStreamPreferredState(value, ppMediaType); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::FlushInputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::FlushInputStream function. + --*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwStreamIndex); + UNREFERENCED_PARAMETER(dwFlags); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + +STDMETHODIMP CMultipinMft::FlushOutputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags + ) + /*++ + Description: + + Implements IMFdeviceTransform::FlushOutputStream function. + Called by the DTM to flush streams + --*/ +{ + + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(dwFlags); + CAutoLock Lock(m_critSec); + + ComPtr spoPin = GetOutPin(dwStreamIndex); + DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG); + DeviceStreamState oldState = spoPin->SetState(DeviceStreamState_Disabled); + DMFTCHECKHR_GOTO(spoPin->FlushQueues(),done); + spoPin->SetState(oldState); +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +/*++ + Description: + + Called when the Device Transform gets a MFT_MESSAGE_COMMAND_FLUSH. We drain all the queues. + This is called in device source when the source gets end of streaming. + --*/ +STDMETHODIMP_(VOID) CMultipinMft::FlushAllStreams( + VOID + ) +{ + DeviceStreamState oldState; + CAutoLock Lock(m_critSec); + for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ ) + { + ComPtr spoPin = (COutPin *)m_OutPins[dwIndex]; + oldState = spoPin->SetState(DeviceStreamState_Disabled); + spoPin->FlushQueues(); + // + //Restore state + // + spoPin->SetState(oldState); + } +} + + +// +// IKsControl interface functions +// +STDMETHODIMP CMultipinMft::KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pulBytesReturned + ) + /*++ + Description: + + Implements IKSProperty::KsProperty function. + used to pass control commands to the driver (generally) + This can be used to intercepted the control to figure out + if it needs to be propogated to the driver or not + --*/ +{ + HRESULT hr = S_OK; + UNREFERENCED_PARAMETER(pulBytesReturned); + DMFTCHECKNULL_GOTO(pProperty, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_INVALIDARG); + + if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Extended Control %d Passed ",pProperty->Id); + } + else if ((IsEqualCLSID(pProperty->Set, PROPSETID_VIDCAP_VIDEOCONTROL)) && (pProperty->Id == KSPROPERTY_VIDEOCONTROL_MODE)) + { + // A function illustrating how we can capture and service photos from the device MFT. This block shows how we can + // intercept Photo triggers going down to the pipeline + + if (sizeof(KSPROPERTY_VIDEOCONTROL_MODE_S) == ulDataLength) + { + PKSPROPERTY_VIDEOCONTROL_MODE_S VideoControl = (PKSPROPERTY_VIDEOCONTROL_MODE_S)pvPropertyData; + m_PhotoModeIsPhotoSequence = false; + if (VideoControl->Mode == KS_VideoControlFlag_StartPhotoSequenceCapture) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Starting PhotoSequence Trigger"); + m_PhotoModeIsPhotoSequence = true; + } + else if (VideoControl->Mode == KS_VideoControlFlag_StopPhotoSequenceCapture) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Stopping PhotoSequence Trigger"); + m_PhotoModeIsPhotoSequence = false; + } + else + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Take Single Photo Trigger"); + } + } + } + DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty, + ulPropertyLength, + pvPropertyData, + ulDataLength, + pulBytesReturned),done); +done: + LPSTR guidStr = DumpGUIDA(pProperty->Set); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! g:%s p:%d exiting %x = %!HRESULT!", guidStr, pProperty->Id, hr, hr); + delete(guidStr); + return hr; +} + +STDMETHODIMP CMultipinMft::KsMethod( + _In_reads_bytes_(ulPropertyLength) PKSMETHOD pMethod, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pulBytesReturned + ) + /*++ + Description: + + Implements IKSProperty::KsMethod function. We can trap ksmethod calls here. + --*/ +{ + return m_spIkscontrol->KsMethod( + pMethod, + ulPropertyLength, + pvPropertyData, + ulDataLength, + pulBytesReturned + ); +} + +STDMETHODIMP CMultipinMft::KsEvent( + _In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ) + /*++ + Description: + + Implements IKSProperty::KsEvent function. + --*/ +{ + + HRESULT hr = S_OK; + { + + // + // All the Events we don't handle should be sent to the driver! + // + hr = m_spIkscontrol->KsEvent(pEvent, + ulEventLength, + pEventData, + ulDataLength, + pBytesReturned); + } + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} + + +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + +// +// IMFTransform function(s). +// + +// +// Note: This is the only IMFTransform function which is not a redirector to the +// DeviceTransform functions. The rest of IMFTransform functions are in the file common.h +// This function returns the IMFAttribute created for Device MFT. If DMFT is +// not loaded (usually )MFT0's call to GetAttributes will get the Attribute store of DevProxy. +// A device MFT loaded will not pass through the devproxy attribute store, but it will pass +// the device MFT attributes. This should be similar to the singular DevProxy attribute +// which the MFT0 providers can use to synchronize across various MFT0's +// + +STDMETHODIMP CMultipinMft::GetAttributes( + _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes + ) +{ + HRESULT hr = S_OK; + CAutoLock Lock(m_critSec); + DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG); + + *ppAttributes = nullptr; + + if (m_spAttributes != nullptr) + { + m_spAttributes.CopyTo(ppAttributes); + } + else + { + hr = E_OUTOFMEMORY; + } + +done: + return hr; +} +#endif + +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) +// +// IMFSampleAllocatorControl Inferface function declarations +// + +STDMETHODIMP CMultipinMft::SetDefaultAllocator( + _In_ DWORD dwOutputStreamID, + _In_ IUnknown *pAllocator +) +{ + CAutoLock Lock(m_critSec); + + // SetAllocator will be called on the streamId that returns MFSampleAllocatorMode_Default + wil::com_ptr_nothrow outPin = GetOutPin(dwOutputStreamID); + RETURN_HR_IF_NULL(E_INVALIDARG, outPin); + RETURN_HR_IF_NULL(E_INVALIDARG, pAllocator); + + wil::com_ptr_nothrow defaultAllocator; + RETURN_IF_FAILED(pAllocator->QueryInterface(&defaultAllocator)); + outPin->SetAllocator(defaultAllocator.get()); + + return S_OK; +} + +STDMETHODIMP CMultipinMft::GetAllocatorUsage( + _In_ DWORD dwOutputStreamID, + _Out_ DWORD* pdwInputStreamID, + _Out_ MFSampleAllocatorUsage* peUsage +) +{ + CAutoLock Lock(m_critSec); + + RETURN_HR_IF_NULL(E_INVALIDARG, peUsage); + + wil::com_ptr_nothrow outPin = GetOutPin(dwOutputStreamID); + RETURN_HR_IF_NULL(MF_E_INVALIDSTREAMNUMBER, outPin); + *peUsage = outPin->GetSampleAllocatorUsage(); + + if (*peUsage == MFSampleAllocatorUsage_DoesNotAllocate) + { + RETURN_HR_IF_NULL(E_INVALIDARG, pdwInputStreamID); + RETURN_IF_FAILED(GetConnectedInpin((ULONG)dwOutputStreamID, *(ULONG*)pdwInputStreamID)); + } + + return S_OK; +} +#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + +// +// HELPER FUNCTIONS +// + +// +// A lock here could mean a deadlock because this will be called when the lock is already held +// in another thread. +// +CInPin* CMultipinMft::GetInPin( + _In_ DWORD dwStreamId +) +{ + CInPin *inPin = NULL; + for (DWORD dwIndex = 0, dwSize = (DWORD)m_InPins.size(); dwIndex < dwSize; dwIndex++) + { + inPin = (CInPin *)m_InPins[dwIndex]; + if (dwStreamId == inPin->streamId()) + { + break; + } + inPin = NULL; + } + return inPin; +} + +COutPin* CMultipinMft::GetOutPin( + _In_ DWORD dwStreamId + ) +{ + COutPin *outPin = NULL; + for ( DWORD dwIndex = 0, dwSize = (DWORD) m_OutPins.size(); dwIndex < dwSize; dwIndex++ ) + { + outPin = ( COutPin * )m_OutPins[ dwIndex ]; + + if ( dwStreamId == outPin->streamId() ) + { + break; + } + + outPin = NULL; + } + + return outPin; +} +_Requires_lock_held_(m_Critsec) +HRESULT CMultipinMft::GetConnectedInpin(_In_ ULONG ulOutpin, _Out_ ULONG &ulInPin) +{ + HRESULT hr = S_OK; + map::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 spoPin = GetOutPin(pinId); + ComPtr spinPin; + DeviceStreamState oldOutPinState, oldInputStreamState, newOutStreamState, newRequestedInPinState; + ComPtr pFullType, pInputMediaType; + ULONG ulInPinId = 0; + DWORD dwFlags = 0; + + + DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG); + { + // + // dump the media types to the logs + // + ComPtr spOldMediaType; + (VOID)spoPin->getMediaType(spOldMediaType.GetAddressOf()); + CMediaTypePrinter newType(pMediaType); + CMediaTypePrinter oldType(spOldMediaType.Get()); + if (WPP_LEVEL_ENABLED(DMFT_GENERAL)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, " Pin:%d old MT:[%s] St:%d", pinId, oldType.ToString(), reqState); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, " Pin:%d new MT:[%s] St:%d", pinId, newType.ToString(), reqState); + } + } + + if (pMediaType) + { + if (!spoPin->IsMediaTypeSupported(pMediaType, &pFullType)) + { + DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done); + } + } + + DMFTCHECKHR_GOTO(GetConnectedInpin(pinId, ulInPinId), done); + spinPin = GetInPin(ulInPinId); // Get the input pin + + (VOID)spinPin->getMediaType(&pInputMediaType); + oldInputStreamState = spinPin->SetState(DeviceStreamState_Disabled); // Disable input pin + oldOutPinState = spoPin->SetState(DeviceStreamState_Disabled); // Disable output pin + (void)spoPin->FlushQueues(); // Flush the output queues + (void)spinPin->FlushQueues(); // Flush the input queues + newOutStreamState = pinStateTransition[oldOutPinState][reqState]; // New state needed + + // The Old input and the output pin states should be the same + newRequestedInPinState = newOutStreamState; + + if ((newOutStreamState != oldOutPinState) /*State change*/ + ||((pFullType.Get() != nullptr) && (pInputMediaType.Get()!=nullptr) && (S_OK != (pFullType->IsEqual(pInputMediaType.Get(), &dwFlags)))) /*Media Types dont match*/ + ||((pFullType == nullptr)||(pInputMediaType == nullptr))/*Either one of the mediatypes is null*/ + ) + { + // + // State has change or media type has changed so we need to change the media type on the + // underlying kernel pin + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Changing Mediatype on the input "); + spinPin->setPreferredMediaType(pFullType.Get()); + spinPin->setPreferredStreamState(newRequestedInPinState); + // Let the pipline know that the input needs to be changed. + SendEventToManager(METransformInputStreamStateChanged, GUID_NULL, spinPin->streamId()); + // + // The media type will be set on the input pin by the time we return from the wait + // + m_critSec.Unlock(); + hr = spinPin->WaitForSetInputPinMediaChange(); + m_critSec.Lock(); + // Change the media type on the output.. + DMFTCHECKHR_GOTO(spoPin->ChangeMediaTypeFromInpin(pFullType.Get(), pMediaType , reqState), done); + // + // Notify the pipeline that the output stream media type has changed + // + DMFTCHECKHR_GOTO(SendEventToManager(MEUnknown, MEDeviceStreamCreated, spoPin->streamId()), done); + spoPin->SetFirstSample(TRUE); + } + else + { + // Restore back old states as we have nothing to do + spinPin->SetState(oldInputStreamState); + spoPin->SetState(oldOutPinState); + } + + +done: + return hr; +} + +// +// The below function sends events to the pipeline. +// + +HRESULT CMultipinMft::SendEventToManager( + _In_ MediaEventType eventType, + _In_ REFGUID pGuid, + _In_ UINT32 context + ) + /*++ + Description: + Used to send the event to DTM. + --*/ + { + HRESULT hr = S_OK; + ComPtr 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 spMediaType; + + DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG ); + DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG ); + // + // Copy over the media types from input pin to output pin. Since there is no + // decoder support, only the uncompressed media types are inserted. Please make + // sure any pin advertised supports at least one media type. The pipeline doesn't + // like pins with no media types + // + while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, spMediaType.ReleaseAndGetAddressOf() ))) + { + GUID subType = GUID_NULL; + DMFTCHECKHR_GOTO( spMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done ); + { + DMFTCHECKHR_GOTO(hr = poPin->AddMediaType(NULL, spMediaType.Get() ), done ); + if (hr == S_OK) + { + ulAddedMediaTypeCount++; + } + } + } + if (ulAddedMediaTypeCount == 0) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Make Sure Pin %d has one media type exposed ", piPin->streamId()); + DMFTCHECKHR_GOTO( MF_E_INVALID_STREAM_DATA, done ); + } + // + //Add the Input Pin to the output Pin + // + DMFTCHECKHR_GOTO(poPin->AddPin(piPin->streamId()), done); + hr = ExceptionBoundary([&](){ + // + // Add the output pin to the input pin. + // Create the pin map. So that we know which pin input pin is connected to which output pin + // + piPin->ConnectPin(poPin); + m_outputPinMap.insert(std::pair< int, int >(poPin->streamId(), piPin->streamId())); + }); + + + +done: + // + //Failed adding media types + // + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + } + return hr; +} + +// +// IMFShutdown interface functions +// + +/*++ +Description: +Implements the Shutdown from IMFShutdown +--*/ +STDMETHODIMP CMultipinMft::Shutdown( + void + ) +{ + CAutoLock Lock(m_critSec); + (VOID) m_eventHandler.Clear(); + + for (ULONG ulIndex = 0, ulSize = (ULONG)m_InPins.size(); ulIndex < ulSize; ulIndex++ ) + { + CInPin *pInPin = static_cast(m_InPins[ulIndex]); + + // Deref on the connected outpins to break reference loop + (VOID)pInPin->ShutdownPin(); + } +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + for (ULONG ulIndex = 0, ulSize = (ULONG)m_OutPins.size(); ulIndex < ulSize; ulIndex++) + { + (VOID) m_OutPins[ulIndex]->DeleteItem(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT); + } +#endif + return ShutdownEventGenerator(); +} + +// +// Static method to create an instance of the MFT. +// +HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT) +{ + HRESULT hr = S_OK; + CMultipinMft *pMFT = NULL; + DMFTCHECKNULL_GOTO(ppMFT, done, E_POINTER); + pMFT = new (std::nothrow) CMultipinMft(); + DMFTCHECKNULL_GOTO(pMFT, done, E_OUTOFMEMORY); + + DMFTCHECKHR_GOTO(pMFT->QueryInterface(iid, ppMFT), done); + +done: + if (FAILED(hr)) + { + SAFERELEASE(pMFT); + } + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} diff --git a/avstream/sampledevicemft/SampleSocDeviceMFT.h b/avstream/sampledevicemft/SampleSocDeviceMFT.h new file mode 100644 index 000000000..91635fb18 --- /dev/null +++ b/avstream/sampledevicemft/SampleSocDeviceMFT.h @@ -0,0 +1,374 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#pragma once +#include "common.h" +#include "mftpeventgenerator.h" +#include "basepin.h" +#include "custompin.h" +#include "multipinmfthelpers.h" + +// +// The Below GUID is needed to transfer photoconfirmation sample successfully in the pipeline +// It is used to propagate the mediatype of the sample to the pipeline which will consume the sample +// This attribute is known to the OS, but not publicly defined. +// + +DEFINE_GUID(MFSourceReader_SampleAttribute_MediaType_priv, + 0x0ea5c1e8, 0x9845, 0x41e0, 0xa2, 0x43, 0x72, 0x32, 0x07, 0xfc, 0x78, 0x1f); + + +interface IDirect3DDeviceManager9; + +// +// Forward declarations +// +class CMFAttributes; +class CPinCreationFactory; +// +// CMultipinMft class: +// Implements a device proxy MFT. +// +class CMultipinMft : + public IMFDeviceTransform +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + , public IMFTransform +#endif + , public IMFShutdown + , public CMediaEventGenerator + , public IMFRealTimeClientEx + , public IKsControl + , public CDMFTModuleLifeTimeManager +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + , public IMFSampleAllocatorControl +#endif +{ + friend class CPinCreationFactory; +public: + CMultipinMft( + void ); + + virtual ~CMultipinMft(); + + // + // IUnknown + // + STDMETHOD_(ULONG, AddRef)( + void ); + + STDMETHOD_(ULONG, Release)( + void ); + + STDMETHOD(QueryInterface)( + _In_ REFIID iid, + _COM_Outptr_ void** ppv); + + + // + // IMFDeviceTransform functions + // + STDMETHOD(GetStreamCount)( + _Inout_ DWORD *pdwInputStreams, + _Inout_ DWORD *pdwOutputStreams); + + + STDMETHOD(GetStreamIDs)( + _In_ DWORD dwInputIDArraySize, + _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs, + _In_ DWORD dwOutputIDArraySize, + _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)), + _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs + ); + + STDMETHOD(GetInputStreamAttributes)( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes); + + STDMETHOD(GetOutputStreamAttributes)( + _In_ DWORD dwOutputStreamID, + _Out_ IMFAttributes** ppAttributes); + + STDMETHOD(GetInputAvailableType)( + _In_ DWORD dwInputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppType); + + STDMETHOD(GetOutputAvailableType)( + _In_ DWORD dwOutputStreamID, + _In_ DWORD dwTypeIndex, + _Out_ IMFMediaType** ppMediaType); + + STDMETHOD(GetInputCurrentType)( + _In_ DWORD dwInputStreamID, + _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType); + + STDMETHOD(GetOutputCurrentType)( + _In_ DWORD dwOutputStreamID, + _Out_ IMFMediaType** ppMediaType); + + STDMETHOD(ProcessMessage)( + _In_ MFT_MESSAGE_TYPE eMessage, + _In_ ULONG_PTR ulParam ); + + STDMETHOD(ProcessEvent)( + _In_ DWORD dwInputStreamID, + _In_ IMFMediaEvent *pEvent); + + + STDMETHOD(ProcessInput)( + _In_ DWORD dwInputStreamID, + _In_ IMFSample* pSample, + _In_ DWORD dwFlags ); + + STDMETHOD(ProcessOutput)( + _In_ DWORD dwFlags, + _In_ DWORD cOutputBufferCount, + _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, + _Out_ DWORD *pdwStatus ); + + // + // IMFRealTimeClientEx + // + STDMETHOD(RegisterThreadsEx)( + _Inout_ DWORD* pdwTaskIndex, + _In_ LPCWSTR wszClassName, + _In_ LONG lBasePriority ) + { + UNREFERENCED_PARAMETER(pdwTaskIndex); + UNREFERENCED_PARAMETER(wszClassName); + UNREFERENCED_PARAMETER(lBasePriority); + return S_OK; + } + + STDMETHOD(UnregisterThreads)() + { + return S_OK; + } + + STDMETHOD(SetWorkQueueEx)( + _In_ DWORD dwWorkQueueId, + _In_ LONG lWorkItemBasePriority ); + + // + // IMFShutdown + // + STDMETHOD(Shutdown)( + void ); + + STDMETHOD(GetShutdownStatus)( + MFSHUTDOWN_STATUS *pStatus) + { + UNREFERENCED_PARAMETER(pStatus); + return(m_eShutdownStatus); + }; + + // + // IMFDeviceTransform function declarations + // + STDMETHODIMP InitializeTransform( + _In_ IMFAttributes *pAttributes ); + + _Requires_no_locks_held_ + STDMETHODIMP SetInputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags ); + + STDMETHODIMP GetInputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value ); + + STDMETHODIMP SetOutputStreamState( + _In_ DWORD dwStreamID, + _In_ IMFMediaType *pMediaType, + _In_ DeviceStreamState value, + _In_ DWORD dwFlags ); + + STDMETHODIMP GetOutputStreamState( + _In_ DWORD dwStreamID, + _Out_ DeviceStreamState *value ); + + STDMETHODIMP GetInputStreamPreferredState( + _In_ DWORD dwStreamID, + _Inout_ DeviceStreamState *value, + _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType ); + + STDMETHODIMP FlushInputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags ); + + STDMETHODIMP FlushOutputStream( + _In_ DWORD dwStreamIndex, + _In_ DWORD dwFlags ); + + STDMETHODIMP_(VOID) FlushAllStreams( + VOID + ); + + // + //IKSControl Inferface function declarations + // + STDMETHOD(KsEvent)( + _In_reads_bytes_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + STDMETHOD(KsProperty)( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + STDMETHOD(KsMethod)( + _In_reads_bytes_(ulPropertyLength) PKSMETHOD pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ ULONG* pBytesReturned + ); + +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + // + // IMFSampleAllocatorControl Inferface function declarations + // + + STDMETHOD(SetDefaultAllocator)( + _In_ DWORD dwOutputStreamID, + _In_ IUnknown *pAllocator + ); + + STDMETHOD(GetAllocatorUsage)( + _In_ DWORD dwOutputStreamID, + _Out_ DWORD* pdwInputStreamID, + _Out_ MFSampleAllocatorUsage* peUsage + ); +#endif + static STDMETHODIMP 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 STDMETHODIMP_(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); +#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES) + STDMETHODIMP CMultipinMft::GetAttributes( + _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes + ); +#endif + +#if (defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)) + _DEFINE_DEVICEMFT_MFT0HELPER_IMPL__ +#endif + + + + // + //Inline functions + // + + __inline IMFTransform* Parent() + { + return m_spSourceTransform.Get(); + } + + __inline VOID SetStreamingState(DeviceStreamState state) + { + InterlockedExchange((LONG*)&m_StreamingState, state); + } + __inline DeviceStreamState GetStreamingState() + { + return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_StreamingState, 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 m_spDeviceManagerUnk; // D3D Manager set, when MFT_MESSAGE_SET_D3D_MANAGER is called through ProcessMessage + ComPtr m_spSourceTransform; // The sources transform. This is the pipeline DevProxy + MFSHUTDOWN_STATUS m_eShutdownStatus; + DWORD m_dwWorkQueueId; + LONG m_lWorkQueuePriority; + UINT32 m_punValue; + ComPtr m_spIkscontrol; + ComPtr m_spAttributes; + map m_outputPinMap; // How output pins are connected to input pins i-><0..outpins> + CDMFTEventHandler m_eventHandler; + PWCHAR m_SymbolicLink; + +}; + + + +inline HRESULT MFT_CreateInstance(REFIID riid, void **ppv) +{ + return CMultipinMft::CreateInstance(riid, ppv); +} + + diff --git a/avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp b/avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp new file mode 100644 index 000000000..1b41496b2 --- /dev/null +++ b/avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp @@ -0,0 +1,1320 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" +#include "common.h" +#include "multipinmft.h" +#include "basepin.h" + +#pragma comment(lib, "d2d1") +#ifdef MF_WPP +#include "multipinmftutils.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif + +// Critical sections + +CCritSec::CCritSec() +{ + InitializeCriticalSection(&m_criticalSection); +} + +CCritSec::~CCritSec() +{ + DeleteCriticalSection(&m_criticalSection); +} + +_Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection) +void CCritSec::Lock() +{ + EnterCriticalSection(&m_criticalSection); +} + +_Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection) +void CCritSec::Unlock() +{ + LeaveCriticalSection(&m_criticalSection); +} + + +_Acquires_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::CAutoLock(CCritSec& crit) +{ + m_pCriticalSection = &crit; + m_pCriticalSection->Lock(); +} +_Acquires_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::CAutoLock(CCritSec* crit) +{ + m_pCriticalSection = crit; + m_pCriticalSection->Lock(); +} +_Releases_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::~CAutoLock() +{ + m_pCriticalSection->Unlock(); +} + +// +//Some utility functions.. +// + +/*++ + Description: + Used to check if the input and the output Image types are optinmized or not +--*/ + +STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair( + _In_ IMFMediaType *inMediaType, + _In_ IMFMediaType *outMediaType, + _Out_ bool *optimized, + _Out_ bool *optimizedxvpneeded ) +{ + HRESULT hr = S_OK; + GUID guidInputSubType = GUID_NULL; + GUID guidOutputSubType = GUID_NULL; + UINT32 uWidthIn = 0, uHeightIn = 0, uWidthOut = 0, uHeightOut = 0; + + + DMFTCHECKHR_GOTO(inMediaType->GetGUID(MF_MT_SUBTYPE, &guidInputSubType), done); + + DMFTCHECKHR_GOTO(outMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done); + + *optimized = false; //Assume we aren't optimized . Optimized = (ip = YU12|NV12 and op = JPEG) + *optimizedxvpneeded = true; //Assume we need xvps + + if (IsEqualGUID(guidInputSubType, MFVideoFormat_YV12) || IsEqualGUID(guidInputSubType, MFVideoFormat_NV12)) + { + if (IsEqualGUID(guidOutputSubType, GUID_ContainerFormatJpeg)) + { + *optimized = true; + } + } + + if (!*optimized) + { + goto done; + } + + DMFTCHECKHR_GOTO(MFGetAttributeSize(inMediaType, MF_MT_FRAME_SIZE, &uWidthIn, &uHeightIn), done); + DMFTCHECKHR_GOTO(MFGetAttributeSize(outMediaType, MF_MT_FRAME_SIZE, &uWidthOut, &uHeightOut), done); + + if ((uWidthIn == uWidthOut) && (uHeightIn == uHeightOut)) + { + *optimizedxvpneeded = false; + } + if (!*optimizedxvpneeded) + { + UINT32 nominalRange; + hr = inMediaType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange); + + if (FAILED(hr) || nominalRange != MFNominalRange_0_255) + { + //XVP needed since nominal range is not 0-255 for YV12 or NV12 fed into WIC + *optimizedxvpneeded = true; + } + hr = S_OK; + } + +done: + return hr; +} + + +/* +Description: + + This is used whenever there is a media type change on an output pin and the + Output queue is being reconfigured. + The possible return values for the function are as follows + + DeviceMftTransformXVPIllegal -> If either of the mediatypes or both are NULL + DeviceMftTransformXVPDisruptiveIn -> If the mediatype at the output pin is greater than the input pin. This will result in change of the media type on the input + DeviceMftTransformXVPDisruptiveOut -> This is a reconfiguration or addition of the XVP in the Output pin queue + DeviceMftTransformXVPCurrent -> No XVP needed at all +*/ +STDMETHODIMP CompareMediaTypesForConverter( + _In_opt_ IMFMediaType *inMediaType, + _In_ IMFMediaType *newMediaType, + _Inout_ PDMFT_conversion_type operation + ) +{ + HRESULT hr = S_OK; + GUID guidTypeA = GUID_NULL; + GUID guidTypeB = GUID_NULL; + + *operation = DeviceMftTransformTypeIllegal; + if ((!inMediaType) || (!newMediaType)) + { + goto done; + } + + if ( SUCCEEDED( inMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeA ) ) && + SUCCEEDED( newMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeB ) ) && + IsEqualGUID( guidTypeA, guidTypeB ) ) + { + if ( SUCCEEDED( inMediaType->GetGUID ( MF_MT_SUBTYPE, &guidTypeA ) ) && + SUCCEEDED( newMediaType->GetGUID( MF_MT_SUBTYPE, &guidTypeB ) ) && + IsEqualGUID( guidTypeA, guidTypeB ) ) + { + BOOL passThrough = TRUE; + DMFTCHECKHR_GOTO(CheckPassthroughMediaType(inMediaType, newMediaType, passThrough), done); + *operation = passThrough?DeviceMftTransformTypeEqual: DeviceMftTransformTypeXVP; + } + else + { + //This is a disruptive operation. Actually a decoder operation! + *operation = DeviceMftTransformTypeDecoder; + } + } + done: + return hr; +} + +/*++ +Description: Used to test if the sample passed is a DX sample or not? +--*/ +HRESULT IsInputDxSample( + _In_ IMFSample* pSample, + _Inout_ BOOL *isDxSample + ) +{ + HRESULT hr = S_OK; + ComPtr spBuffer = nullptr; + DMFTCHECKNULL_GOTO( pSample, done, E_INVALIDARG ); + + *isDxSample = false; + if ( SUCCEEDED( pSample->GetBufferByIndex( 0, &spBuffer ) ) ) + { + ComPtr spDXGIBuffer; + ComPtr spResourceTexture; + if ( SUCCEEDED( spBuffer.As(&spDXGIBuffer ) ) && + SUCCEEDED( spDXGIBuffer-> GetResource( IID_PPV_ARGS( &spResourceTexture ) ) ) ) + { + *isDxSample = true; + } + } +done: + return hr; +} + + +/*++ + Description: + Helper function to return back if the Pin is in stopped stateo or not +--*/ +STDMETHODIMP_(BOOL) IsPinStateInActive( _In_ DeviceStreamState state) +{ + if ((state == DeviceStreamState_Disabled) || + (state == DeviceStreamState_Stop)) + { + return TRUE; + } + return FALSE; +} + +/* +Description: + A Helper function to return if the Mediatype is a compressed video type or not! +*/ +STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType(_In_ GUID guidSubType) +{ + if (guidSubType == MFVideoFormat_ARGB32 || + guidSubType == MFVideoFormat_RGB24 || + guidSubType == MFVideoFormat_RGB555 || + guidSubType == MFVideoFormat_RGB565 || + guidSubType == MFVideoFormat_RGB32 || + guidSubType == MFVideoFormat_RGB8 || + guidSubType == MFVideoFormat_AI44 || + guidSubType == MFVideoFormat_AYUV || + guidSubType == MFVideoFormat_YUY2 || + guidSubType == MFVideoFormat_YVYU || + guidSubType == MFVideoFormat_YVU9 || + guidSubType == MFVideoFormat_UYVY || + guidSubType == MFVideoFormat_NV11 || + guidSubType == MFVideoFormat_NV12 || + guidSubType == MFVideoFormat_YV12 || + guidSubType == MFVideoFormat_I420 || + guidSubType == MFVideoFormat_IYUV || + guidSubType == MFVideoFormat_Y210 || + guidSubType == MFVideoFormat_Y216 || + guidSubType == MFVideoFormat_Y410 || + guidSubType == MFVideoFormat_Y416 || + guidSubType == MFVideoFormat_Y41P || + guidSubType == MFVideoFormat_Y41T || + guidSubType == MFVideoFormat_Y42T || + guidSubType == MFVideoFormat_P210 || + guidSubType == MFVideoFormat_P216 || + guidSubType == MFVideoFormat_P010 || + guidSubType == MFVideoFormat_P016 || + guidSubType == MFVideoFormat_v210 || + guidSubType == MFVideoFormat_v216 || + guidSubType == MFVideoFormat_v410 || + guidSubType == MFVideoFormat_L8 || + guidSubType == MFVideoFormat_L16 || + guidSubType == MFVideoFormat_D16) + { + return( TRUE ); + } + + return( FALSE ); +} + +#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); }\ +} + + +/*++ +Description: + returns an ascii buffer for the GUID passed. The Caller should release the memory allocated +--*/ +LPSTR DumpGUIDA(_In_ REFGUID guid) +{ + LPOLESTR lpszGuidString = NULL; + char *ansiguidStr = NULL; + if (SUCCEEDED(StringFromCLSID(guid, &lpszGuidString))) + { + int mbGuidLen = 0; + mbGuidLen = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, NULL, 0, NULL, NULL); + if (mbGuidLen > 0) + { + mf_assert(mbGuidLen == (int)wcslen(lpszGuidString)); + ansiguidStr = new (std::nothrow) char[mbGuidLen]; + if (ansiguidStr) + { + WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, ansiguidStr, mbGuidLen, NULL, NULL); + CoTaskMemFree(lpszGuidString); + ansiguidStr[mbGuidLen - 1] = 0; + } + } + } + return ansiguidStr; +} + +// +//Borrrowed from MDSN sample +// +LPCSTR GetGUIDNameConst(const GUID& guid) +{ + IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE); + IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT); + IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES); + IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED); + IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE); + IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX); + IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN); + IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO); + IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING); + IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE); + IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES); + IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES); + IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE); + IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED); + IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE); + IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE); + IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING); + IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE); + IF_EQUAL_RETURN(guid, MF_MT_PALETTE); + IF_EQUAL_RETURN(guid, MF_MT_USER_DATA); + IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1); + IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK); + IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK); + IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER); + IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT); + IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT); + IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION); + IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY); + IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC); + IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG); + + // Media types + + IF_EQUAL_RETURN(guid, MFMediaType_Audio); + IF_EQUAL_RETURN(guid, MFMediaType_Video); + IF_EQUAL_RETURN(guid, MFMediaType_Protected); + IF_EQUAL_RETURN(guid, MFMediaType_SAMI); + IF_EQUAL_RETURN(guid, MFMediaType_Script); + IF_EQUAL_RETURN(guid, MFMediaType_Image); + IF_EQUAL_RETURN(guid, MFMediaType_HTML); + IF_EQUAL_RETURN(guid, MFMediaType_Binary); + IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer); + + IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44') + IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV') + IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25') + IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl') + IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264') + IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420') + IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV') + IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2') + IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG); + IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43') + IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S') + IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V') + IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1') + IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1') + IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2') + IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11') + IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12') + IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010') + IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016') + IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210') + IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216') + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8); + IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY') + IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210') + IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3') + IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P); + IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T); + IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2') + IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12') + IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU); + + IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM + IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT + IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS + IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF + IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2 + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3 + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS + IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF + IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9 + IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3 + IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG + IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC + IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC + + return NULL; +} + + +LPSTR DumpAttribute( _In_ const MF_ATTRIBUTE_TYPE& type, + _In_ REFPROPVARIANT var) +{ + CHAR *tempStr = NULL; + tempStr = new (std::nothrow) CHAR[256]; + switch (type) + { + case MF_ATTRIBUTE_UINT32: + if (var.vt == VT_UI4) + { + sprintf_s(tempStr, 256, "%u", var.ulVal); + } + break; + case MF_ATTRIBUTE_UINT64: + if (var.vt == VT_UI8) + { + sprintf_s(tempStr, 256, "%I64d (high: %d low: %d)", var.uhVal.QuadPart, var.uhVal.HighPart, var.uhVal.LowPart); + } + break; + case MF_ATTRIBUTE_DOUBLE: + if (var.vt == VT_R8) + { + sprintf_s(tempStr, 256, "%.4f", var.dblVal); + } + break; + case MF_ATTRIBUTE_GUID: + if (var.vt == VT_CLSID) + { + return DumpGUIDA(*var.puuid); + } + break; + case MF_ATTRIBUTE_STRING: + if (var.vt == VT_LPWSTR) + { + sprintf_s(tempStr, 256, "%S", var.pwszVal); + } + break; + case MF_ATTRIBUTE_IUNKNOWN: + break; + default: + printf("(Unknown Attribute Type = %d) ", type); + break; + } + return tempStr; +} + +CMediaTypePrinter::CMediaTypePrinter( + _In_ IMFMediaType *_pMediaType ) + : pMediaType(_pMediaType), + m_pBuffer(NULL) +{ +} + +CMediaTypePrinter::~CMediaTypePrinter() +{ + if (m_pBuffer) + { + delete(m_pBuffer); + } +} + +/*++ +Description: +Rudimentary function to print the complete Media type +--*/ +PCHAR CMediaTypePrinter::ToCompleteString( ) +{ + HRESULT hr = S_OK; + UINT32 attrCount = 0; + GUID attrGuid = { 0 }; + char *tempStore = nullptr; + PROPVARIANT var; + LPSTR pTempBaseStr; + MF_ATTRIBUTE_TYPE pType; + + if ( pMediaType && !m_pBuffer ) + { + DMFTCHECKHR_GOTO(pMediaType->GetCount(&attrCount), done); + buffLen = MEDIAPRINTER_STARTLEN; + m_pBuffer = new char[buffLen]; + DMFTCHECKNULL_GOTO(m_pBuffer, done, E_OUTOFMEMORY); + m_pBuffer[0] = 0; + for ( UINT32 ulIndex = 0; ulIndex < attrCount; ulIndex++ ) + { + PropVariantInit( &var ); + checkAdjustBufferCap( m_pBuffer, buffLen ); + DMFTCHECKHR_GOTO( pMediaType->GetItemByIndex( ulIndex, &attrGuid, &var ), done ); + DMFTCHECKHR_GOTO( pMediaType->GetItemType( attrGuid, &pType ), done ); + if ( ulIndex > 0 ) + strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : "); + strcat_s( m_pBuffer, buffLen, GetGUIDNameConst( attrGuid ) ); + strcat_s( m_pBuffer, buffLen, "=" ); + pTempBaseStr = DumpAttribute( pType, var ); + strcat_s( m_pBuffer, buffLen, pTempBaseStr ); + delete( pTempBaseStr ); + PropVariantClear( &var ); + } + done: + if ( tempStore ) + { + delete( tempStore ); + } + } + return m_pBuffer; +} + +/*++ +Description: +Rudimentary function to print the Media type +--*/ + +PCHAR CMediaTypePrinter::ToString() +{ + // + //Following are the important ones of Mediatype attributes + // + + HRESULT hr = S_OK; + PROPVARIANT var; + LPSTR pTempBaseStr; + MF_ATTRIBUTE_TYPE pType; + GUID attrGuid; + GUID impGuids[] = { + MF_MT_SUBTYPE, + MF_MT_FRAME_SIZE, + MF_MT_SAMPLE_SIZE, + MF_MT_FRAME_RATE, + MF_MT_DEFAULT_STRIDE, + MF_XVP_DISABLE_FRC + }; + + if (pMediaType && !m_pBuffer) + { + buffLen = MEDIAPRINTER_STARTLEN; + m_pBuffer = new (std::nothrow) char[buffLen]; + DMFTCHECKNULL_GOTO(m_pBuffer, done, E_OUTOFMEMORY); + m_pBuffer[0] = 0; + for (UINT32 ulIndex = 0; ulIndex < ARRAYSIZE(impGuids); ulIndex++) + { + PropVariantInit(&var); + checkAdjustBufferCap(m_pBuffer, buffLen); + attrGuid = impGuids[ulIndex]; + DMFTCHECKHR_GOTO(pMediaType->GetItemType(attrGuid, &pType), done); + DMFTCHECKHR_GOTO(pMediaType->GetItem(attrGuid, &var), done); + if (ulIndex > 0) + strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : "); + strcat_s(m_pBuffer, buffLen, GetGUIDNameConst(attrGuid)); + strcat_s(m_pBuffer, buffLen, "="); + pTempBaseStr = DumpAttribute(pType, var); + strcat_s(m_pBuffer, buffLen, pTempBaseStr); + delete(pTempBaseStr); + PropVariantClear(&var); + } + } +done: + return m_pBuffer; +} +/*++ +Description: + Debug message printer to print the message passed through WPP +--*/ +void printMessageEvent(MFT_MESSAGE_TYPE msg) +{ + switch (msg) + { + case MFT_MESSAGE_COMMAND_FLUSH: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_FLUSH"); + break; + case MFT_MESSAGE_COMMAND_DRAIN: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_DRAIN"); + break; + case MFT_MESSAGE_COMMAND_MARKER: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_MARKER"); + break; + case MFT_MESSAGE_COMMAND_TICK: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_TICK"); + break; + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_END_OF_STREAM"); + break; + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_BEGIN_STREAMING"); + break; + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_START_OF_STREAM"); + break; + case MFT_MESSAGE_DROP_SAMPLES: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_DROP_SAMPLES"); + break; + case MFT_MESSAGE_SET_D3D_MANAGER: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_SET_D3D_MANAGER"); + break; + + } +} + +HRESULT GetDXGIAdapterLuid(_In_ IMFDXGIDeviceManager *pDXManager, _Out_ LUID &AdapterLuid) +{ + HRESULT hr = S_OK; + ComPtr spDevice; + ComPtr spDXGIDevice; + ComPtr spDXGIAdapter; + DXGI_ADAPTER_DESC adapterDesc = { 0 }; + HANDLE hDevice = NULL; + + DMFTCHECKNULL_GOTO(pDXManager, done, E_INVALIDARG); + + DMFTCHECKHR_GOTO(pDXManager->OpenDeviceHandle(&hDevice), done); + DMFTCHECKHR_GOTO(pDXManager->GetVideoService(hDevice, IID_PPV_ARGS(&spDevice)), done); + DMFTCHECKHR_GOTO(spDevice->QueryInterface(IID_PPV_ARGS(&spDXGIDevice)), done); + DMFTCHECKHR_GOTO(spDXGIDevice->GetAdapter(&spDXGIAdapter), done); + DMFTCHECKHR_GOTO(spDXGIAdapter->GetDesc(&adapterDesc), done); + + CopyMemory(&AdapterLuid, &adapterDesc.AdapterLuid, sizeof(LUID)); + +done: + if (NULL != hDevice) + { + pDXManager->CloseDeviceHandle(hDevice); + } + + return hr; +} + +HRESULT EnumSWDecoder(_Outptr_ IMFTransform** ppTransform, _In_ GUID subType) +{ + HRESULT hr = S_OK; + IMFActivate** ppActivate = nullptr; + UINT32 count = 0; + ComPtr spTransform; + LPWSTR pszFriendlyName = nullptr; + + MFT_REGISTER_TYPE_INFO info = { MFMediaType_Video, subType }; + UINT32 unFlags = MFT_ENUM_FLAG_SYNCMFT | + MFT_ENUM_FLAG_LOCALMFT | + MFT_ENUM_FLAG_SORTANDFILTER; + + DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG); + *ppTransform = nullptr; + + DMFTCHECKHR_GOTO(MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, unFlags, + &info, // Input type + NULL, // Output type + &ppActivate, + &count + ), done); + + + if (count == 0) + { + DMFTCHECKHR_GOTO(MF_E_TOPO_CODEC_NOT_FOUND, done); + } + + if (SUCCEEDED(MFGetAttributeString(ppActivate[0], MFT_FRIENDLY_NAME_Attribute, &pszFriendlyName))) + { + // + // Log the friendly name of the decoder + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! decoder name: %S ", (pszFriendlyName ? pszFriendlyName : L"UnknownCodec")); + SAFE_COTASKMEMFREE(pszFriendlyName); + } + + DMFTCHECKHR_GOTO(ppActivate[0]->ActivateObject(IID_PPV_ARGS(spTransform.GetAddressOf())), done); + + *ppTransform = spTransform.Detach(); + +done: + if (ppActivate) + { + for (UINT32 uiIndex = 0; uiIndex < count; uiIndex++) + { + ppActivate[uiIndex]->Release(); + } + CoTaskMemFree(ppActivate); + } + return hr; +} +// +// @@@@ README Create the decoder +// +HRESULT CreateDecoderFromLuid( _In_ LUID ullAdapterLuidRunningOn, + _In_ IMFMediaType* pInputType, + _In_ IMFMediaType* pOutputType, + _Inout_ BOOL fHwMft, + _Outptr_ IMFTransform** ppDecoder) +{ + HRESULT hr = S_OK; + ComPtr spAttribs; + ComPtr spMJPGDecoder; + IMFActivate **ppActivates = nullptr; + DWORD dwFlags = MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_HARDWARE | 0x10000000 /*Internal attribute*/; + UINT32 cMFTActivate = 0; + MFT_REGISTER_TYPE_INFO InputType; + MFT_REGISTER_TYPE_INFO OutputType; + GUID compressedGUID; + ComPtr spD3D11Device; + + fHwMft = FALSE; + + + DMFTCHECKNULL_GOTO(pInputType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pOutputType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(ppDecoder, done, E_INVALIDARG); + *ppDecoder = nullptr; + DMFTCHECKHR_GOTO(pInputType->GetGUID(MF_MT_SUBTYPE, &compressedGUID), done); + + InputType.guidMajorType = MFMediaType_Video; + InputType.guidSubtype = compressedGUID; + + DMFTCHECKHR_GOTO(pOutputType->GetMajorType(&OutputType.guidMajorType), done); + DMFTCHECKHR_GOTO(pOutputType->GetGUID(MF_MT_SUBTYPE, &OutputType.guidSubtype), done); + + DMFTCHECKHR_GOTO(MFCreateAttributes(&spAttribs, 1), done); + DMFTCHECKHR_GOTO(spAttribs->SetBlob(MFT_ENUM_ADAPTER_LUID, (byte*)&ullAdapterLuidRunningOn, sizeof(ullAdapterLuidRunningOn)), done); + DMFTCHECKHR_GOTO(MFTEnum2(MFT_CATEGORY_VIDEO_DECODER, dwFlags, &InputType, &OutputType, spAttribs.Get(), &ppActivates, &cMFTActivate), done); + + for (DWORD i = 0; i < cMFTActivate; i++) + { + HRESULT hrTemp = ppActivates[i]->ActivateObject(IID_PPV_ARGS(spMJPGDecoder.GetAddressOf())); + fHwMft = (MFT_ENUM_FLAG_HARDWARE & MFGetAttributeUINT32(ppActivates[i], MF_TRANSFORM_FLAGS_Attribute, 0)); + // Pickup the first MFT enumerated. Normally, it should be a HW MFT, if HWMFT is available. + if (SUCCEEDED(hrTemp)) + { + break; + } + else + { + spMJPGDecoder = nullptr; + } + } + if (spMJPGDecoder == nullptr) + { + hr = MF_E_NOT_FOUND; + } + *ppDecoder = spMJPGDecoder.Detach(); +done: + + for (UINT32 i = 0; i < cMFTActivate; i++) + { + if (nullptr != ppActivates[i]) + { + ppActivates[i]->Release(); + } + } + SAFE_COTASKMEMFREE(ppActivates); + return hr; +} + +HRESULT SetDX11BindFlags( _In_ IUnknown *pUnkManager, + _In_ GUID guidPinCategory, + _Inout_ DWORD &dwBindFlags) +{ + HRESULT hr = S_OK; + ComPtr spDeviceManager; + BOOL fFL10 = FALSE; + + auto + IsFeatureLevel10OrBetter = [&]() -> BOOL + { + ComPtr spDXGIManager; + ComPtr spDevice; + HANDLE hDevice = 0; + BOOL fRet = FALSE; + UINT level = 0, result = 0; + + if (SUCCEEDED(pUnkManager->QueryInterface(IID_PPV_ARGS(&spDXGIManager))) && + SUCCEEDED(spDXGIManager->OpenDeviceHandle(&hDevice)) && + SUCCEEDED(spDXGIManager->LockDevice(hDevice, IID_PPV_ARGS(&spDevice), FALSE))) + { + + level = (UINT)spDevice->GetFeatureLevel(); + fRet = (level >= D3D_FEATURE_LEVEL_10_0); + if (!fRet) + { + if (SUCCEEDED(spDevice->CheckFormatSupport(DXGI_FORMAT_NV12, &result))) + { + fRet = (result & D3D11_FORMAT_SUPPORT_TEXTURE2D) && (result & D3D11_FORMAT_SUPPORT_RENDER_TARGET); + } + } + (void)spDXGIManager->UnlockDevice(hDevice, FALSE); + (void)spDXGIManager->CloseDeviceHandle(hDevice); + } + return fRet; + }; + + DMFTCHECKNULL_GOTO(pUnkManager, done, E_INVALIDARG); + fFL10 = IsFeatureLevel10OrBetter(); + + dwBindFlags |= fFL10 ? D3D11_BIND_SHADER_RESOURCE : 0; + dwBindFlags |= (guidPinCategory != PINNAME_VIDEO_PREVIEW) ? D3D11_BIND_VIDEO_ENCODER : 0; + if ((dwBindFlags != 0) && ((dwBindFlags & ~(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_VIDEO_ENCODER)) == 0)) + { + dwBindFlags |= D3D11_BIND_RENDER_TARGET; + } +done: + return hr; +} + +// @@@@ README: Create the Decoder +HRESULT CreateDecoderHW(_In_ IMFDXGIDeviceManager* pManager, + _In_ IMFMediaType* inType, + _In_ IMFMediaType* outType, + _Outptr_ IMFTransform** ppTransform, + _Inout_ BOOL& fHwMft) +{ + HRESULT hr = S_OK; + LUID luid; + ComPtr spTransform; + DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG); + *ppTransform = nullptr; + + if (pManager) + { + if (SUCCEEDED(hr = GetDXGIAdapterLuid(pManager, luid))) + { + hr = CreateDecoderFromLuid(luid, inType, outType, fHwMft, spTransform.GetAddressOf()); + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Error creating HW Decoder with LUID %d-%d", luid.HighPart, luid.LowPart); + DMFTCHECKHR_GOTO(hr, done); + } + } + } + *ppTransform = spTransform.Detach(); +done: + return hr; +} + +HRESULT +SubtypeToDXGIFormat( + _In_ GUID subType, + _Inout_ DXGI_FORMAT &format +) +{ + HRESULT hr = S_OK; + typedef struct { + GUID subType; + DXGI_FORMAT format; + }DXGIFormatMap; + DXGIFormatMap formatMap[] + { + { MFVideoFormat_NV12, DXGI_FORMAT_NV12 }, + { MFVideoFormat_YUY2, DXGI_FORMAT_YUY2 }, + { MFVideoFormat_RGB32, DXGI_FORMAT_B8G8R8X8_UNORM }, + { MFVideoFormat_ARGB32, DXGI_FORMAT_B8G8R8A8_UNORM }, + { MFVideoFormat_AYUV, DXGI_FORMAT_AYUV }, + { MFVideoFormat_NV11, DXGI_FORMAT_NV11 }, + { MFVideoFormat_AI44, DXGI_FORMAT_AI44 }, + { MFVideoFormat_P010, DXGI_FORMAT_P010 }, + { MFVideoFormat_P016, DXGI_FORMAT_P016 }, + { MFVideoFormat_Y210, DXGI_FORMAT_Y210 }, + { MFVideoFormat_Y216, DXGI_FORMAT_Y216 }, + { MFVideoFormat_Y410, DXGI_FORMAT_Y410 }, + { MFVideoFormat_Y416, DXGI_FORMAT_Y416 }, + }; + format = DXGI_FORMAT_UNKNOWN; + for (UINT32 uiIndex = 0; uiIndex < _countof(formatMap); uiIndex++) + { + if (formatMap[uiIndex].subType == subType) + { + format = formatMap[uiIndex].format; + break; + } + } + // compressed media type or unsupported of the range + hr = (format == DXGI_FORMAT_UNKNOWN) ? E_NOTIMPL : S_OK; + return hr; +} + +HRESULT IsDXFormatSupported( + _In_ IMFDXGIDeviceManager* pDeviceManager , + _In_ GUID subType, + _Outptr_opt_ ID3D11Device** ppDevice, + _In_opt_ PUINT32 pSupportedFormat) +{ + HRESULT hr = S_OK; + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + UINT32 supportedFormat = 0; + HANDLE hDevice = NULL; + ComPtr spDevice; + DMFTCHECKNULL_GOTO(pDeviceManager, done, E_INVALIDARG); + DMFTCHECKHR_GOTO(pDeviceManager->OpenDeviceHandle(&hDevice), done); + DMFTCHECKHR_GOTO(pDeviceManager->GetVideoService(hDevice, IID_PPV_ARGS(&spDevice)), done); + DMFTCHECKHR_GOTO(SubtypeToDXGIFormat(subType, format), done); + DMFTCHECKHR_GOTO(spDevice->CheckFormatSupport(format, &supportedFormat), done); + if (pSupportedFormat) + { + *pSupportedFormat = supportedFormat; + } + if (ppDevice) + { + *ppDevice = spDevice.Detach(); + } +done: + if (hDevice != NULL) + { + pDeviceManager->CloseDeviceHandle(hDevice); + } + return hr; +} + +HRESULT +UpdateAllocatorAttributes( + _In_ IMFAttributes *pAttributes, + _In_ REFGUID guidStreamCategory, + _In_ GUID subType, + _In_ IMFDXGIDeviceManager *pDeviceManager +) +{ + HRESULT hr = S_OK; + UINT32 supportedFormat = 0; + ComPtr spDevice; + DWORD dwBindFlags = 0; + + DMFTCHECKHR_GOTO(IsDXFormatSupported(pDeviceManager,subType, + spDevice.GetAddressOf(),&supportedFormat),done); + + // MF_SA_D3D11_USAGE should be D3D11_USAGE_DEFAULT, same as previous release. + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_USAGE, D3D11_USAGE_DEFAULT), done); + + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE), done); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_SHARED_WITH_NTHANDLE_PRIVATE, TRUE), done); + + // Bind Flags + dwBindFlags |= ((supportedFormat & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0 ? D3D11_BIND_RENDER_TARGET : 0); + + if (((supportedFormat & D3D11_FORMAT_SUPPORT_VIDEO_ENCODER) != 0) && + (!IsEqualGUID(guidStreamCategory, PINNAME_VIDEO_PREVIEW)) && + IsEqualGUID(subType, MFVideoFormat_NV12)) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS4 Options = { 0 }; + + // "D3D11_BIND_VIDEO_ENCODER + sharing" is only supported on those devices that + // advertise ExtendedNV12SharedTextureSupported. + DMFTCHECKHR_GOTO(spDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS4, &Options, sizeof(Options)), done); + if (Options.ExtendedNV12SharedTextureSupported) + { + dwBindFlags |= D3D11_BIND_VIDEO_ENCODER; + } + } + + // D3D requires one of the flags (D3D11_BIND_RENDER_TARGET, D3D11_PRIVATE_BIND_CAPTURE, or D3D11_BIND_VIDEO_ENCODER) to be set for non-zero bind flags. + if (dwBindFlags != 0) + { + D3D_FEATURE_LEVEL level; + + // D3D11_BIND_SHADER_RESOURCE + level = spDevice->GetFeatureLevel(); + dwBindFlags |= ((level >= D3D_FEATURE_LEVEL_10_0) ? D3D11_BIND_SHADER_RESOURCE : 0); + } + + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_BINDFLAGS, dwBindFlags), done); + +done: + return hr; +} + +const UINT32 ALLOCATOR_MIN_SAMPLES = 10; +const UINT32 ALLOCATOR_MAX_SAMPLES = 50; + +HRESULT ConfigureAllocator( + _In_ IMFMediaType* pOutputMediaType, + _In_ GUID streamCategory, + _In_ IUnknown* pDeviceManagerUnk, + _In_ BOOL &bDxAllocator, + _In_ IMFVideoSampleAllocator* pAllocator) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow spPrivateAllocator; +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + wil::com_ptr_nothrow spDefaultAllocator; +#endif + wil::com_ptr_nothrow spAllocatorAttributes; + GUID guidMajorType = GUID_NULL; + GUID guidSubtype = GUID_NULL; + BOOL fDXAllocator = FALSE; + + RETURN_HR_IF_NULL(E_INVALIDARG, pAllocator ); + RETURN_HR_IF_NULL(E_INVALIDARG, pOutputMediaType ); + + RETURN_IF_FAILED(pOutputMediaType->GetMajorType(&guidMajorType)); + + if (!IsEqualGUID(guidMajorType, MFMediaType_Video)) + { + RETURN_HR(MF_E_INVALIDMEDIATYPE); + } + + RETURN_IF_FAILED(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubtype)); + // + // Set Attributes on the allocator we need. First get the Bind Flags. + // + RETURN_IF_FAILED(MFCreateAttributes(&spAllocatorAttributes, 8)); + RETURN_IF_FAILED(spAllocatorAttributes->SetUINT32(MF_SA_BUFFERS_PER_SAMPLE, 1)); + + if (pDeviceManagerUnk != nullptr) + { + if (SUCCEEDED(UpdateAllocatorAttributes(spAllocatorAttributes.get(), streamCategory, guidSubtype, (IMFDXGIDeviceManager*)pDeviceManagerUnk))) + { + fDXAllocator = TRUE; + } + } + + if (fDXAllocator) + { + RETURN_IF_FAILED(pAllocator->SetDirectXManager(pDeviceManagerUnk)); + } + + if (SUCCEEDED(pAllocator->QueryInterface(IID_PPV_ARGS(&spPrivateAllocator)))) + { + RETURN_IF_FAILED(spPrivateAllocator->InitializeSampleAllocatorEx( + ALLOCATOR_MIN_SAMPLES, + ALLOCATOR_MAX_SAMPLES, + spAllocatorAttributes.get(), + pOutputMediaType)); + } +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + else if (SUCCEEDED(pAllocator->QueryInterface(IID_PPV_ARGS(&spDefaultAllocator)))) + { + RETURN_IF_FAILED(spDefaultAllocator->InitializeCaptureSampleAllocator( + 0, /*use sample size by MediaType*/ + 0, /*metadata size*/ + 0, /*default alignment*/ + ALLOCATOR_MIN_SAMPLES, + spAllocatorAttributes.get(), + pOutputMediaType)); + } +#endif + else + { + hr = E_INVALIDARG; + } + + bDxAllocator = fDXAllocator; + + return hr; +} +// +//@@@@ README: Creating an Allocator.. Please don't allocate samples individually using MFCreateSample as that can lead to fragmentation and is +// extremely inefficent. Instead create an Allocator which will create a fixed number of samples which are recycled when the pipeline returns back +// the buffers. The above has defines will enable to create a circular allocator which will have maximum 20 samples flowing in the pipeline +// This way we can also catch samples leaks if any. +// +HRESULT CreateAllocator( _In_ IMFMediaType* pOutputMediaType, + _In_ GUID streamCategory, + _In_ IUnknown* pDeviceManagerUnk, + _In_ BOOL &bDxAllocator, + _Outptr_ IMFVideoSampleAllocatorEx** ppAllocator ) +{ + HRESULT hr = S_OK; + ComPtr spVideoSampleAllocator; + ComPtr spAllocatorAttributes; + GUID guidMajorType = GUID_NULL; + GUID guidSubtype = GUID_NULL; + BOOL fDXAllocator = FALSE; + + DMFTCHECKNULL_GOTO(ppAllocator, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pOutputMediaType, done, E_INVALIDARG); + DMFTCHECKHR_GOTO(pOutputMediaType->GetMajorType(&guidMajorType), done); + + *ppAllocator = nullptr; + if (!IsEqualGUID(guidMajorType, MFMediaType_Video)) + { + DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done); + } + + DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubtype), done); + // + // Set Attributes on the allocator we need. First get the Bind Flags. + // + DMFTCHECKHR_GOTO(MFCreateAttributes(&spAllocatorAttributes, 8), done); + DMFTCHECKHR_GOTO(spAllocatorAttributes->SetUINT32(MF_SA_BUFFERS_PER_SAMPLE, 1), done); + + if (pDeviceManagerUnk != nullptr) + { + if (SUCCEEDED(UpdateAllocatorAttributes(spAllocatorAttributes.Get(), streamCategory,guidSubtype, (IMFDXGIDeviceManager*)pDeviceManagerUnk))) + { + fDXAllocator = TRUE; + } + } + DMFTCHECKHR_GOTO(MFCreateVideoSampleAllocatorEx(IID_PPV_ARGS(spVideoSampleAllocator.ReleaseAndGetAddressOf())), done); + if (fDXAllocator) + { + DMFTCHECKHR_GOTO(spVideoSampleAllocator->SetDirectXManager(pDeviceManagerUnk), done); + } + + DMFTCHECKHR_GOTO(spVideoSampleAllocator->InitializeSampleAllocatorEx(ALLOCATOR_MIN_SAMPLES, ALLOCATOR_MAX_SAMPLES, spAllocatorAttributes.Get(), pOutputMediaType), done); + + *ppAllocator = spVideoSampleAllocator.Detach(); + bDxAllocator = fDXAllocator; +done: + return hr; +} + +HRESULT CheckPassthroughMediaType(_In_ IMFMediaType *pMediaType1, + _In_ IMFMediaType *pMediaType2, + _Out_ BOOL& pfPassThrough) +{ + HRESULT hr = S_OK; + BOOL fPassThrough = FALSE; + UINT32 uWidth, uHeight; + UINT32 uWidth2, uHeight2; + + // Compare Width/Height. + DMFTCHECKHR_GOTO(MFGetAttributeSize(pMediaType1, MF_MT_FRAME_SIZE, &uWidth, &uHeight), done); + DMFTCHECKHR_GOTO(MFGetAttributeSize(pMediaType2, MF_MT_FRAME_SIZE, &uWidth2, &uHeight2), done); + if ((uWidth != uWidth2) || (uHeight != uHeight2)) + { + goto done; + } + + // Compare rotation + { + UINT32 uRotation; + UINT32 uRotation2; + + uRotation = MFGetAttributeUINT32(pMediaType1, MF_MT_VIDEO_ROTATION, 0); + uRotation2 = MFGetAttributeUINT32(pMediaType2, MF_MT_VIDEO_ROTATION, 0); + if (uRotation != uRotation2) + { + goto done; + } + } + + // Compare Aspect Ratio + { + UINT32 uNumerator = 1, uDenominator = 1; + UINT32 uNumerator2 = 1, uDenominator2 = 1; + + (void)MFGetAttributeRatio(pMediaType1, MF_MT_FRAME_RATE, &uNumerator, &uDenominator); + (void)MFGetAttributeRatio(pMediaType2, MF_MT_FRAME_RATE, &uNumerator2, &uDenominator2); + if ((uNumerator * uDenominator2) != (uNumerator2 * uDenominator)) + { + goto done; + } + } + + // Compare Nominal Range + { + UINT32 uNorminalRange; + UINT32 uNorminalRange2; + + uNorminalRange = MFGetAttributeUINT32(pMediaType1, MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Unknown); + uNorminalRange2 = MFGetAttributeUINT32(pMediaType2, MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Unknown); + if (uNorminalRange != uNorminalRange2) + { + goto done; + } + } + + // Compare color primaries + { + UINT32 uPrimaries; + UINT32 uPrimaries2; + + uPrimaries = MFGetAttributeUINT32(pMediaType1, MF_MT_VIDEO_PRIMARIES, MFVideoPrimaries_Unknown); + uPrimaries2 = MFGetAttributeUINT32(pMediaType2, MF_MT_VIDEO_PRIMARIES, MFVideoPrimaries_Unknown); + if (uPrimaries != uPrimaries2) + { + goto done; + } + } + + + // Compare InterlaceMode + { + UINT32 uInterlaceMode; + UINT32 uInterlaceMode2; + + uInterlaceMode = MFGetAttributeUINT32(pMediaType1, MF_MT_INTERLACE_MODE, MFVideoInterlace_Unknown); + uInterlaceMode2 = MFGetAttributeUINT32(pMediaType2, MF_MT_INTERLACE_MODE, MFVideoInterlace_Unknown); + if (uInterlaceMode != uInterlaceMode2) + { + goto done; + } + } + + // Compare display aperture + { + MFVideoArea VideoArea = { 0 }; + MFVideoArea VideoArea2 = { 0 }; + UINT32 cbBlobSize = 0; + + if (SUCCEEDED(pMediaType1->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&VideoArea, sizeof(MFVideoArea), &cbBlobSize))) + { + if ((VideoArea.OffsetX.value == 0 && VideoArea.OffsetX.fract == 0) && + (VideoArea.OffsetY.value == 0 && VideoArea.OffsetY.fract == 0) && + (VideoArea.Area.cx == (LONG)uWidth) && + (VideoArea.Area.cy == (LONG)uHeight)) + { + // If the display aperture is the whole frame size, ignore it. + ZeroMemory(&VideoArea, sizeof(VideoArea)); + } + } + + if (SUCCEEDED(pMediaType2->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&VideoArea2, sizeof(MFVideoArea), &cbBlobSize))) + { + if ((VideoArea2.OffsetX.value == 0 && VideoArea2.OffsetX.fract == 0) && + (VideoArea2.OffsetY.value == 0 && VideoArea2.OffsetY.fract == 0) && + (VideoArea2.Area.cx == (LONG)uWidth) && + (VideoArea2.Area.cy == (LONG)uHeight)) + { + // If the display aperture is the whole frame size, ignore it. + ZeroMemory(&VideoArea, sizeof(VideoArea)); + } + } + + if (memcmp(&VideoArea, &VideoArea2, sizeof(MFVideoArea)) != 0) + { + goto done; + } + } + + fPassThrough = TRUE; + +done: + pfPassThrough = fPassThrough; + return hr; +} + + +HRESULT MergeSampleAttributes( _In_ IMFSample* pInSample, _Inout_ IMFSample* pOutSample) +{ + HRESULT hr = S_OK; + UINT32 cAttributes = 0; + GUID guidAttribute; + PROPVARIANT varAttribute; + PROPVARIANT varAttributeExists; + PropVariantInit(&varAttribute); + PropVariantInit(&varAttributeExists); + + DMFTCHECKNULL_GOTO(pInSample, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pOutSample, done, E_INVALIDARG); + + DMFTCHECKHR_GOTO(pInSample->GetCount(&cAttributes), done); + for (UINT32 i = 0; i < cAttributes; i++) + { + PropVariantClear(&varAttribute); + PropVariantClear(&varAttributeExists); + + DMFTCHECKHR_GOTO(pInSample->GetItemByIndex(i, &guidAttribute, &varAttribute), done); + + if (S_OK == pOutSample->GetItem(guidAttribute, &varAttributeExists)) + { + // Exists.. dont clobber + continue; + } + + DMFTCHECKHR_GOTO(pOutSample->SetItem(guidAttribute, varAttribute), done); + } + +done: + PropVariantClear(&varAttribute); + PropVariantClear(&varAttributeExists); + return hr; +}