summaryrefslogtreecommitdiff
path: root/AVStream/sampledevicemft/multipinmfthelpers.cpp
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2017-03-17 19:47:04 -0700
committerWei Mao <[email protected]>2017-03-17 19:47:04 -0700
commit1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch)
treebf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /AVStream/sampledevicemft/multipinmfthelpers.cpp
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'AVStream/sampledevicemft/multipinmfthelpers.cpp')
-rw-r--r--AVStream/sampledevicemft/multipinmfthelpers.cpp988
1 files changed, 988 insertions, 0 deletions
diff --git a/AVStream/sampledevicemft/multipinmfthelpers.cpp b/AVStream/sampledevicemft/multipinmfthelpers.cpp
new file mode 100644
index 00000000..078ca337
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmfthelpers.cpp
@@ -0,0 +1,988 @@
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmfthelpers.h"
+#include "multipinmft.h"
+#include "basepin.h"
+#include <wincodec.h>
+
+#ifdef MF_WPP
+#include "multipinmfthelpers.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+class CMediaTypePrinter;
+//
+//Queue implementation
+//
+
+CPinQueue::CPinQueue( _In_ DWORD _InpinId )
+: m_teer(0),
+ m_discotinuity(0),
+ m_sampleCount(0),
+ m_dwInPinId(_InpinId)
+ /*
+ Description
+ _InpinId is the input pin Id to which this queue corresponds
+ */
+{
+}
+CPinQueue::~CPinQueue( )
+{
+}
+
+/*++
+Description:
+ Insert sample into the list once we reach the open queue
+--*/
+STDMETHODIMP_(VOID) CPinQueue::InsertInternal( _In_ IMFSample *pSample )
+{
+ pSample->AddRef();
+ HRESULT hr = ExceptionBoundary([&]()
+ {
+ m_sampleList.push_back(pSample);
+ });
+
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ SAFE_RELEASE(pSample);
+ }
+}
+
+STDMETHODIMP_(BOOL) CPinQueue::Insert( _In_ IMFSample *pSample )
+//
+//m_teer is the wraptee.. this could be a null tee which is a passthrough, an xvp tee, which inserts an xvp into the queue
+//
+{
+ return SUCCEEDED( m_teer->PassThrough( pSample, this ) );
+}
+
+
+/*++
+Description:
+ This extracts the first sample from the queue. called from Pin's ProcessOutput
+--*/
+
+STDMETHODIMP_(BOOL) CPinQueue::Remove( _Outptr_result_maybenull_ IMFSample **ppSample)
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO( ppSample, done,E_INVALIDARG );
+ *ppSample = nullptr;
+
+ if ( !m_sampleList.empty() )
+ {
+ *ppSample = m_sampleList.front();
+ }
+
+ DMFTCHECKNULL_GOTO( *ppSample, done, MF_E_TRANSFORM_NEED_MORE_INPUT );
+
+ (*ppSample)->Release( );
+
+ m_sampleList.erase( m_sampleList.begin() );
+done:
+ return SUCCEEDED( hr ) ? TRUE : FALSE;
+}
+
+/*++
+Description:
+ Empties the Queue. used by the flush
+--*/
+VOID CPinQueue::Clear( )
+{
+ IMFSample* pSample = nullptr;
+ while ( !Empty() )
+ {
+ Remove( &pSample );
+ SAFE_RELEASE( pSample );
+ }
+}
+
+/*++
+Description:
+ RecreateTee creates the underlying Tees in the queue. It accepts the input media type
+ which is the media type set on the input pin and the output mediatype, which (duh) is the
+ media type on the output pin
+ It also takes an IUnknown which is the D3D Manager. if it is valid we might use it if we
+ have an xvp in the path i.e. inputMediatype =! outputMediatype
+--*/
+
+STDMETHODIMP CPinQueue::RecreateTee( _In_ IMFMediaType *inMediatype,
+ _In_ IMFMediaType *outMediatype,
+ _In_opt_ IUnknown* punkManager )
+{
+ HRESULT hr = S_OK;
+ MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal;
+
+ DMFTCHECKNULL_GOTO(inMediatype, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(outMediatype, done, E_INVALIDARG);
+
+ SAFE_DELETE(m_teer);
+
+ CNullTee *nulltee = new (std::nothrow) CNullTee();
+ DMFTCHECKNULL_GOTO( nulltee, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO( CompareMediaTypesForXVP(inMediatype, outMediatype, &operation), done);
+
+ if ( (operation != DeviceMftTransformXVPCurrent) && (operation!= DeviceMftTransformXVPIllegal) )
+ {
+ CXvptee* pXvptee = new (std::nothrow) CXvptee(nulltee);
+ DMFTCHECKNULL_GOTO(pXvptee, done, E_OUTOFMEMORY);
+ (void)pXvptee->SetD3DManager( punkManager );
+ (void)pXvptee->SetMediaTypes( inMediatype, outMediatype );
+ m_teer = dynamic_cast< Ctee* >( pXvptee );
+ }
+ else
+ {
+ m_teer = nulltee; /*A simple passthrough*/
+ }
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+
+ if (FAILED(hr))
+ {
+ if (m_teer){
+ delete(m_teer);
+ m_teer = NULL;
+ }
+
+ }
+ return hr;
+}
+
+//
+//State implementation
+//
+CPinOpenState::CPinOpenState(CBasePin *_pin)
+:CPinState(DeviceStreamState_Run), m_pin(_pin)
+{
+
+}
+
+
+
+/*++
+Description:
+ This is the passthrough Tee in the literal sense i.e. It just dumps the sample
+ into the queue qupplied as an argument
+--*/
+STDMETHODIMP CNullTee::PassThrough( _In_ IMFSample *pSample, _In_ CPinQueue *que )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(pSample, done, S_OK); //No OP for a NULL Sample!!!
+ (VOID)que->InsertInternal(pSample);
+
+ done:
+ return hr;
+}
+
+/*++
+Description:
+ This function sets the Media types on the XVP or the decoder transform. Here is where we configure the XVP
+ or the Decoder or the Encoder tee if present. The first iteration only has the XVP added
+--*/
+STDMETHODIMP CWrapTee::SetMediaTypes( _In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType )
+{
+ HRESULT hr = S_OK;
+ IMFTransform *pTransform = nullptr;
+
+ DMFTCHECKHR_GOTO(Configure( pInMediaType, pOutMediaType, &pTransform ),done);
+ m_videoProcessor = pTransform;
+ m_pInputMediaType = pInMediaType;
+ m_pOutputMediaType = pOutMediaType;
+
+done:
+ SAFE_RELEASE(pTransform);
+ return hr;
+}
+
+/*++
+Description:
+This is used when an XVP is present in the Pin. If the path is a passthrough i.e.
+the media type on the input and the output pins are the same then we will not see
+this path traversed. This function feeds the sample to the XVP or the decoding Tee
+--*/
+STDMETHODIMP CWrapTee::PassThrough(_In_ IMFSample* pInSample, _In_ CPinQueue *pQue)
+{
+ HRESULT hr = S_OK;
+ IMFSample* pOutSample = nullptr;
+
+ DMFTCHECKHR_GOTO(Do(pInSample, &pOutSample),done);
+
+ if (m_objectWrapped)
+ {
+ hr = m_objectWrapped->PassThrough(pOutSample, pQue);
+ }
+
+done:
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ }
+
+ return hr;
+}
+
+
+/*++
+CXvptee::Do
+Description:
+Called to do what an XVP is supposed to do i.e. scaling, resize etc.
+This function is called when the samples are desposited from the input pin to the
+output pin queue during a ProcessInput call on the device transform. Of course the
+outpin should be in Open state for the sample to reach the XVP and consequetively the
+Output Pin.
+
+If the DX manager is set on the Transform and we receieve a DX sample then we will
+undertake the DX transform in the XVP else we will skip it and go the software way
+--*/
+STDMETHODIMP CXvptee::Do(_In_ IMFSample *pSample, _Outptr_ IMFSample** pOutSample)
+{
+ //
+ //Since we are streaming in the software mode we will create a new sample
+ //
+ HRESULT hr = S_OK,pohr = S_OK;
+ MFT_OUTPUT_DATA_BUFFER outputSample;
+ MFT_OUTPUT_STREAM_INFO StreamInfo;
+ IMFSample* spXVPOutputSample = nullptr;
+ IMFMediaType* pOutMediaType = nullptr;
+ ComPtr <IMFMediaBuffer> spIMFMediaBuffer = nullptr;
+ GUID guidOutputSubType = GUID_NULL;
+ pOutMediaType = getOutMediaType();
+
+ DMFTCHECKNULL_GOTO(pOutSample, done, E_INVALIDARG);
+
+ DMFTCHECKHR_GOTO(pOutMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done);
+
+ BOOL isDx = false;
+
+ if (SUCCEEDED(IsInputDxSample(pSample, &isDx)) && isDx)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! DX Sample sent to XVP %p", pSample);
+ }
+
+ outputSample.dwStreamID = 0;
+ outputSample.pSample = NULL;
+
+ if (!(isDx && m_spDeviceManagerUnk!=nullptr))
+ {
+ //
+ //Create a new sample for software encoding
+ //
+ DMFTCHECKHR_GOTO(MFCreateSample(&spXVPOutputSample), done);
+
+ DMFTCHECKHR_GOTO(pSample->CopyAllItems(spXVPOutputSample), done);
+
+ outputSample.pSample = spXVPOutputSample;
+
+
+ DMFTCHECKHR_GOTO(Transform()->MFTGetOutputStreamInfo(0, &StreamInfo), done);
+
+ if (!m_isOutPutImage)
+ {
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pOutMediaType, MF_MT_FRAME_SIZE, &m_uWidth, &m_uHeight), done);
+ hr = MFCreate2DMediaBuffer(
+ m_uWidth,
+ m_uHeight,
+ guidOutputSubType.Data1,
+ FALSE, // top-down buffer (DX compatible)
+ &spIMFMediaBuffer);
+ if (FAILED(hr))
+ {
+ spIMFMediaBuffer = nullptr;
+ spXVPOutputSample->Release();
+
+ DMFTCHECKHR_GOTO(MFCreateAlignedMemoryBuffer(
+ StreamInfo.cbSize,
+ StreamInfo.cbAlignment,
+ &spIMFMediaBuffer), done);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured without DX, Created a 1D buffer");
+
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured with DX, Created a 2D buffer");
+ }
+ DMFTCHECKHR_GOTO(spXVPOutputSample->AddBuffer(spIMFMediaBuffer.Get()), done);
+ }
+ }
+
+
+ //
+ //Start streaming the xvp transform..
+ //
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), done); // ulParam set to zero
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), done); // ulParam set to zero
+
+
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessInput(0, pSample, 0),done);
+
+ DWORD dwStatus = 0;
+
+ pohr = Transform()->MFTProcessOutput(0, 1, &outputSample, &dwStatus);
+
+ if (FAILED(pohr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP ProcessOutput,failure %x sample =%p", pohr, &outputSample);
+ SAFERELEASE(spXVPOutputSample);
+ }
+
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), done); // Flush the stream
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0), done); // Notify end of stream
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0), done); // Notify end of streaming
+
+ spXVPOutputSample = outputSample.pSample;
+
+ if ( SUCCEEDED(pohr) )
+ {
+ //Let us copy the timestamps
+ LONGLONG hnsSampleDuration = 0;
+ LONGLONG hnsSampleTime = 0;
+
+ pSample->GetSampleDuration(&hnsSampleDuration);
+ pSample->GetSampleTime(&hnsSampleTime);
+ spXVPOutputSample->SetSampleDuration(hnsSampleDuration);
+ spXVPOutputSample->SetSampleTime(hnsSampleTime);
+ }
+
+ *pOutSample = spXVPOutputSample;
+ //
+ //Release the Sample back to the pipeline
+ //
+ pSample->Release();
+
+done:
+ hr = FAILED(pohr) ? pohr : hr;
+ return hr;
+}
+
+/*++
+Description:
+ Set the D3D Manager on the XVP
+--*/
+STDMETHODIMP_(VOID) CXvptee::SetD3DManager(IUnknown* pUnk)
+{
+ m_spDeviceManagerUnk = pUnk;
+}
+/*++
+Descrtiption:
+ Create the XVP Transform with the media types supplied.
+ This is invoked when an XVP is added to the Queue in the Output pins
+ and the input pins media type and the output pins media type don't match.
+
+--*/
+STDMETHODIMP CXvptee::Configure(
+ _In_opt_ IMFMediaType* inMediaType,
+ _In_opt_ IMFMediaType* outMediaType,
+ _Outptr_ IMFTransform **ppTransform
+ )
+{
+ HRESULT hr = S_OK;
+ GUID inMajorType = GUID_NULL;
+ GUID outMajorType = GUID_NULL;
+ bool imageType = false;
+ bool optimized = false;
+ bool optimizedxvpneeded = false;
+ IMFMediaType *pXvpOutputMediaType = nullptr;
+ ComPtr<IMFAttributes> pXvpTransformAttributes = nullptr;
+ UINT32 width = 0, height = 0;
+
+ DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG);
+
+ m_isOutPutImage = false;
+ m_isoptimizedPlanarInputOutput = false;
+
+ //
+ //Print out the Media type set on the XVP
+ //
+ {
+ CMediaTypePrinter inType(inMediaType);
+ CMediaTypePrinter outType(outMediaType);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Input MediaType %s", inType.ToString());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Output MediaType %s", outType.ToString());
+ }
+
+ DMFTCHECKHR_GOTO( CoCreateInstance(
+ CLSID_VideoProcessorMFT,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(ppTransform)), done);
+
+
+
+ DMFTCHECKHR_GOTO( inMediaType->GetMajorType( &inMajorType ),done );
+ DMFTCHECKHR_GOTO( outMediaType->GetMajorType( &outMajorType ), done );
+ //
+ //Configuring DX Manager in SW mode. We will look to make it DX complaint in the next phase
+ //
+ if ( !IsEqualGUID(MFMediaType_Video, outMajorType ) )
+ {
+ imageType = true;
+ m_isOutPutImage = true;
+ IsOptimizedPlanarVideoInputImageOutputPair(
+ inMediaType,
+ outMediaType,
+ &optimized,
+ &optimizedxvpneeded );
+ }
+
+ //
+ //Disable frame rate conversion
+ //
+ DMFTCHECKHR_GOTO((*ppTransform)->GetAttributes(&pXvpTransformAttributes),done);
+ pXvpTransformAttributes->SetUINT32(MF_XVP_DISABLE_FRC, TRUE);
+ DMFTCHECKHR_GOTO( (*ppTransform)->MFTProcessMessage( MFT_MESSAGE_SET_D3D_MANAGER, NULL ), done );
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetInputType(0, inMediaType, 0), done);
+
+
+ DMFTCHECKHR_GOTO(MFCreateMediaType(&pXvpOutputMediaType), done);
+ DMFTCHECKHR_GOTO(outMediaType->CopyAllItems(pXvpOutputMediaType), done);
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), done); //Video propcessor doesn't understand image types
+
+
+ if ( imageType )
+ {
+ GUID guidSub;
+
+ if ( !optimized )
+ {
+ DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done );
+ if ( IsEqualGUID( guidSub, MFVideoFormat_ARGB32 ) )
+ {
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), done);
+ }
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done);
+
+ m_uWidth = width;
+ m_uHeight = height;
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, width * 4), done); //So we always get a top down buffer
+
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done);
+ }
+ else
+ {
+ //*** If we come here we know that the XVP is needed
+ //This case should be for non planar and xvp needed cases which we will always assume
+ LONG cStride = 0;
+ //For now we will just assume that we need the xvp in all cases
+ DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done );
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, guidSub), done);
+
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done);
+
+ DMFTCHECKHR_GOTO( MFGetStrideForBitmapInfoHeader( guidSub.Data1, width, &cStride ), done );
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, cStride), done); //So we always get a top down buffer for Nv12/Yv12
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255), done); //Always set nominal range to 0-255 to feed into a WIC encoder
+
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done);
+ }
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, outMediaType, 0), done);
+ }
+ if ((m_spDeviceManagerUnk != nullptr))
+ {
+ //
+ //Set the D3D Manager on the XVP if present
+ //
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER,
+ reinterpret_cast<ULONG_PTR>(m_spDeviceManagerUnk.Get())), done);
+ }
+done:
+ SAFE_RELEASE(pXvpOutputMediaType);
+ return hr;
+
+}
+
+
+CXvptee::CXvptee( _In_ Ctee *tee) :
+CWrapTee(tee),
+ m_isOutPutImage(false),
+ m_isoptimizedPlanarInputOutput(true),
+ m_spDeviceManagerUnk(nullptr),
+ m_uHeight(0),
+ m_uWidth(0)
+
+{
+
+}
+
+
+CXvptee::~CXvptee()
+{
+ m_spDeviceManagerUnk = nullptr;
+}
+
+//To be implemented..Not needed for the sample!!
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+STDMETHODIMP CDecoderTee::Do(_In_ IMFSample* pSample, _Out_ IMFSample **pOutSample )
+{
+ UNREFERENCED_PARAMETER(pSample);
+ UNREFERENCED_PARAMETER(pOutSample);
+ return S_OK;
+}
+STDMETHODIMP CDecoderTee::Configure( _In_opt_ IMFMediaType *inMediaType, _In_opt_ IMFMediaType *outMediaType, _Outptr_ IMFTransform** ppTransform)
+{
+ HRESULT hr = S_OK;
+ GUID guidcategory = GUID_NULL;
+ BOOL IsDecoder = true;
+ UINT32 unFlags = 0;
+ MFT_REGISTER_TYPE_INFO in;
+ MFT_REGISTER_TYPE_INFO out;
+ UINT32 cActivates = 0;
+ UINT32 unMFTFlags = 0;
+ ComPtr<IMFMediaType> pInputMediaType = nullptr;
+ ComPtr<IMFMediaType> pOutputMediaType = nullptr;
+ IMFActivate **ppActivates = nullptr;
+ DWORD dwInputStreams;
+ DWORD dwOutputStreams;
+ UNREFERENCED_PARAMETER(outMediaType);
+ UNREFERENCED_PARAMETER(inMediaType);
+ UNREFERENCED_PARAMETER(ppTransform);
+
+ guidcategory = (IsDecoder)?MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_ENCODER;
+
+ if (IsDecoder)
+ {
+ DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &in.guidMajorType), done);
+ DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_SUBTYPE, &in.guidSubtype), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &out.guidMajorType), done);
+ DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &out.guidSubtype), done);
+ }
+
+ //
+ //Use all possible plugins
+ //
+
+ unFlags = MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_SORTANDFILTER_WEB_ONLY;
+ DMFTCHECKHR_GOTO(MFTEnumEx(guidcategory,
+ unFlags,
+ IsDecoder ? &in : NULL,
+ IsDecoder ? NULL : &out,
+ &ppActivates,
+ &cActivates
+ ),done);
+ if (cActivates!=0)
+ {
+ DMFTCHECKHR_GOTO(MF_E_TOPO_CODEC_NOT_FOUND, done);
+ }
+ for (DWORD dwIndex = 0; dwIndex < cActivates; dwIndex++)
+ {
+ //
+ //Check if this MFT requires an unlocking.. skip if it does
+ //
+ unMFTFlags = MFGetAttributeUINT32(ppActivates[dwIndex], MF_TRANSFORM_FLAGS_Attribute, 0);
+ if (unMFTFlags & MFT_ENUM_FLAG_FIELDOFUSE)
+ {
+ //
+ //If you have the unlocking key set MFT_FIELDOFUSE_UNLOCK_Attribute on the activate
+ //
+ continue;
+ }
+
+ hr = ppActivates[dwIndex]->ActivateObject(IID_PPV_ARGS(ppTransform));
+ if (FAILED(hr))
+ continue; //hope the next activate is activable
+ ppActivates[dwIndex]->DetachObject();
+
+ hr = (*ppTransform)->MFTGetStreamCount(&dwInputStreams, &dwOutputStreams);
+
+ if (FAILED(hr) || dwInputStreams != 1 || dwOutputStreams > 127)//remove the hardcoding
+ {
+ //
+ //Exception.. we can't use a stream that doesn't give us an idea about it's streams
+ //
+ continue;
+ }
+ if (IsDecoder)
+ {
+ hr = ConfigureDecoder(*ppTransform);
+ }
+ else
+ {
+ hr = ConfigureEncoder(*ppTransform);
+ }
+ if (FAILED(hr))
+ {
+ SAFE_RELEASE(*ppTransform);
+ }
+ }
+
+done:
+ return hr;
+}
+
+/*++
+
+--*/
+
+STDMETHODIMP CDecoderTee::ConfigureEncoder( _In_ IMFTransform *pTransform )
+{
+ HRESULT hr = S_OK;
+ //
+ //Set the input media type and the output media type and that should be pretty much it
+ //
+ ComPtr<IMFMediaType> pInputType = nullptr;
+ ComPtr<IMFMediaType> pOutputType = nullptr;
+
+ pInputType = getInMediaType();
+ pOutputType = getOutMediaType();
+
+ if (pInputType && pOutputType)
+ {
+ //We should be good by now
+ DMFTCHECKHR_GOTO( pTransform->MFTSetInputType( 0,pInputType.Get(), 0), done);
+ //If we have D3D enabled then try again with D3D disabled and see the result
+ //
+ DMFTCHECKHR_GOTO(pTransform->MFTSetOutputType(0,pOutputType.Get(), 0), done);
+ //
+ //If the above operation fails and we are allowing partial media types then
+ //we have to find the full media type and then check again
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+done:
+ return hr;
+}
+
+STDMETHODIMP CDecoderTee::ConfigureDecoder( _In_ IMFTransform *pTransform)
+{
+ UNREFERENCED_PARAMETER( pTransform );
+ return S_OK;
+}
+
+/*++
+Descrtiption:
+ Handles events sent by the pipeline
+ --*/
+STDMETHODIMP CDMFTEventHandler::KSEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned)
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(ulDataLength);
+ UNREFERENCED_PARAMETER(pBytesReturned);
+
+ if (pEvent == nullptr)
+ {
+ //
+ // We can have an Event Reset here
+ //
+ if (pEventData == nullptr)
+ {
+ //
+ // Invalid input. KSEVENT and KSEVENTDATA cannot both be null
+ //
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ //
+ // The way KSevents work are, KSEVENT and KSEVENTDATA both have to be non null for events to be Set
+ // on the driver. If the pipeline wishes to reset the event we pass the KSEVENT structure as NULL and
+ // the KSEVENTDATA to be nonnull.
+ // ********** EVENT RESET here since KSEVENT is null and KSEVENTDATA is not**********
+ // We will never get Event Reset for One shot events
+ // Search the list of regular events to find the KSEVENTDATA pointer and then free the entry
+ //
+ for ( vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it )
+ {
+ PDMFTEventEntry pEntry = nullptr;
+ pEntry = *it;
+ DMFTCHECKNULL_GOTO(pEntry, done, E_UNEXPECTED); // We should never see a null data structure entry
+ if (pEntry->m_pEventData == pEventData)
+ {
+ it = m_RegularEventList.erase(it);
+ delete(pEntry); // Delete the entry!
+ goto done;
+ }
+ }
+
+ DMFTCHECKHR_GOTO(E_NOT_SET, done);
+ }
+ else
+ {
+ //
+ // If we are here the pipeline wants to do the following things
+ // 1) Store a regular event
+ // 2) Store a oneshot event
+ //
+ HANDLE evtHandle = nullptr;
+ PKSEVENT pEvt = pEvent;
+ PKSEVENTDATA pEvtdata = reinterpret_cast<PKSEVENTDATA>(pEventData);
+
+ if (ulEventLength < sizeof(KSEVENT))
+ {
+ DMFTCHECKNULL_GOTO(pBytesReturned, done, E_INVALIDARG);
+ *pBytesReturned = sizeof(KSEVENT);
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+
+ if (!pEvtdata)
+ {
+ //
+ // Need the event data to be present to service the call properly!
+ //
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+
+ if (pEvt->Flags & KSEVENT_TYPE_ENABLE) // Regular/ Manual Reset Event
+ {
+ vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin();
+ for (; it != m_RegularEventList.end(); it++)
+ {
+ PDMFTEventEntry pEntry = *it;
+ DMFTCHECKNULL_GOTO(pEntry, done, E_FAIL);
+ if (pEntry->m_pEventData == pEventData)
+ {
+ break;
+ }
+ }
+ if (it != m_RegularEventList.end())
+ {
+ //
+ // Duplicate entry found.
+ //
+ DMFTCHECKHR_GOTO(E_NOT_VALID_STATE, done);
+ }
+ }
+ else if (pEvt->Flags & KSEVENT_TYPE_ONESHOT)
+ {
+ ULONG ulEventCommand = pEvt->Id;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventCommand);
+ if (it != m_OneShotEventMap.end())
+ {
+ //
+ // Duplicate entry found.
+ //
+ hr = E_NOT_VALID_STATE;
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_NOTIMPL, done);
+ }
+
+ //
+ // Duplicate the handle
+ //
+ DMFTCHECKHR_GOTO(Dupe(pEvtdata->EventHandle.Event, &evtHandle),done);
+ ULONG ulEventCommand = pEvt->Id;
+
+ if (pEvt->Flags & KSEVENT_TYPE_ENABLE)
+ {
+ // ************** REGULAR EVENT ****************************
+ // Regualar event. When this needs to be cleqared we will geta call with KSEVENT = null
+ // and KSEVENTDATA with the same address as this call(pEvtdata). Hence store it
+ // To set the event all we need is the EVENT id.
+ //
+ PDMFTEventEntry pEntry = new DMFTEventEntry(ulEventCommand, pEvtdata, evtHandle);
+ DMFTCHECKNULL_GOTO(pEntry, done, E_OUTOFMEMORY);
+ hr = ExceptionBoundary([&]()
+ {
+ (VOID)m_RegularEventList.push_back(pEntry);
+ });
+ }
+ else if(pEvt->Flags & KSEVENT_TYPE_ONESHOT)
+ {
+ // *************** SINGLE SHOT EVENT ************************
+ // Single Shot event store. Store the event Id and the Handle.
+ //
+ hr = ExceptionBoundary([&]()
+ {
+ (VOID)m_OneShotEventMap.insert(std::pair<ULONG, HANDLE>(ulEventCommand, evtHandle));
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ }
+
+done:
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Used to set the One shot events sent by the pipeline.
+ One shot events should be closed by the component after firing. The Pipeline
+ will not send a reset or a clear for one shot events
+--*/
+
+STDMETHODIMP CDMFTEventHandler::SetOneShot( ULONG ulEventId )
+{
+ HRESULT hr = S_OK;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventId);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! trying to Set OneShot %d ", ulEventId);
+
+ if (it != m_OneShotEventMap.end())
+ {
+ // Found the event
+ HANDLE hOneShot = it->second;
+ if (SetEvent(hOneShot))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d Succeeded",
+ ulEventId);
+ CloseHandle(hOneShot);
+ m_OneShotEventMap.erase(it);
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x",
+ ulEventId,
+ HRESULT_FROM_WIN32(GetLastError()));
+ }
+ }
+ else
+ {
+ hr = E_NOT_SET;
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x",
+ ulEventId,
+ HRESULT_FROM_WIN32(GetLastError()));
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Used to set the Regular events sent by the pipeline.
+ Regular events unlike the one shot events must be persisted
+ until the pipeline explicitly needs the event to be unset.
+--*/
+
+STDMETHODIMP CDMFTEventHandler::SetRegularEvent(ULONG ulEventId)
+{
+ BOOL bEvtFound = FALSE;
+ HRESULT hr = ExceptionBoundary([&]()
+ {
+
+ for (vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it)
+ {
+ PDMFTEventEntry pEntry = *it;
+ if (ulEventId == pEntry->m_ulEventId)
+ {
+ // Found the event
+ bEvtFound = TRUE;
+ if (!::SetEvent(pEntry->m_hHandle))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d Failed 0x%x",
+ ulEventId, hr);
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d s",
+ ulEventId);
+ }
+ }
+ }
+ });
+ if (!bEvtFound)
+ {
+ DMFTCHECKHR_GOTO(E_NOT_SET, done);
+ }
+done:
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Duplicates the handle passed.
+--*/
+
+STDMETHODIMP CDMFTEventHandler::Dupe(_In_ HANDLE hEventHandle, _Outptr_ LPHANDLE lpTargetHandle)
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO(hEventHandle, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(lpTargetHandle, done, E_INVALIDARG);
+ //
+ // Duplicate handle and store it for when it needs to be fired
+ //
+ if (!DuplicateHandle(GetCurrentProcess(), hEventHandle,
+ GetCurrentProcess(), lpTargetHandle,
+ 0,
+ false,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Duplicating Event Handle failed %x",
+ hr);
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+done:
+ return hr;
+}
+
+/*++
+
+Descrtiption:
+ Cleans the event lists, both the Single shot and the Regular ones
+
+--*/
+STDMETHODIMP CDMFTEventHandler::Clear()
+{
+ HRESULT hr = S_OK;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.begin();
+ for (; it != m_OneShotEventMap.end(); ++it)
+ {
+ //
+ // Delete the one shot entries. We should not see this path usually
+ // as the pipeline will send a one shot event and set it soon. We
+ // should remore the entry then.
+ //
+ CloseHandle(it->second);
+ it = m_OneShotEventMap.erase(it);
+ if (it == m_OneShotEventMap.end())
+ {
+ // We've reached the end break
+ break;
+ }
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ hr = ExceptionBoundary([=]()
+ {
+ vector<PDMFTEventEntry>::iterator it2 = m_RegularEventList.begin();
+ for (; it2 != m_RegularEventList.end(); ++it2)
+ {
+ //
+ // Delete the entries. This will be traversed
+ //
+ PDMFTEventEntry pEntry = *it2;
+ it2 = m_RegularEventList.erase(it2);
+ SAFE_DELETE(pEntry);
+ if (it2 == m_RegularEventList.end())
+ {
+ break;
+ }
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+done:
+ return hr;
+}