summaryrefslogtreecommitdiff
path: root/avstream/sampledevicemft
diff options
context:
space:
mode:
Diffstat (limited to 'avstream/sampledevicemft')
-rw-r--r--avstream/sampledevicemft/basepin.cpp171
-rw-r--r--avstream/sampledevicemft/basepin.h64
-rw-r--r--avstream/sampledevicemft/common.h11
-rw-r--r--avstream/sampledevicemft/contosodevice.h28
-rw-r--r--avstream/sampledevicemft/custompin.cpp2
-rw-r--r--avstream/sampledevicemft/dllmain.cpp24
-rw-r--r--avstream/sampledevicemft/multipinmft.cpp60
-rw-r--r--avstream/sampledevicemft/multipinmft.h20
-rw-r--r--avstream/sampledevicemft/multipinmft.vcxproj8
-rw-r--r--avstream/sampledevicemft/multipinmft.vcxproj.Filters1
-rw-r--r--avstream/sampledevicemft/multipinmfthelpers.cpp396
-rw-r--r--avstream/sampledevicemft/multipinmfthelpers.h211
-rw-r--r--avstream/sampledevicemft/multipinmftutils.cpp86
-rw-r--r--avstream/sampledevicemft/packages.config4
-rw-r--r--avstream/sampledevicemft/stdafx.h7
15 files changed, 842 insertions, 251 deletions
diff --git a/avstream/sampledevicemft/basepin.cpp b/avstream/sampledevicemft/basepin.cpp
index d4220397..563ff610 100644
--- a/avstream/sampledevicemft/basepin.cpp
+++ b/avstream/sampledevicemft/basepin.cpp
@@ -3,6 +3,7 @@
#include "multipinmft.h"
#include "multipinmfthelpers.h"
#include "basepin.h"
+#include "contosodevice.h"
#ifdef MF_WPP
#include "basepin.tmh" //--REF_ANALYZER_DONT_REMOVE--
@@ -323,7 +324,7 @@ STDMETHODIMP CInPin::WaitForSetInputPinMediaChange()
if ( dwWait != WAIT_OBJECT_0 )
{
- hr = E_FAIL;
+ hr = HRESULT_FROM_WIN32(GetLastError());
goto done;
}
done:
@@ -384,23 +385,79 @@ HRESULT CInPin::SetInputStreamState(
return hr;
}
-void CInPin::ReleaseConnectedPins()
+STDMETHODIMP_(VOID) CInPin::ShutdownPin()
{
m_spSourceTransform = nullptr;
m_outpin = nullptr;
}
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+//
+// ForwardSecureBuffer()
+//
+// Parameters:
+// sample - The sample to send out for secure processing
+//
+// Returns:
+// HRESULT
+//
+// Notes:
+// This helper function calls back to the AVstream driver for post-processing of a
+// secure buffer. This is done here as an example for simplicity. A more realistic
+// scenario might have you calling into an ISP driver that is not an AVstream driver.
+// To do that you would need to acquire a handle to that device and post an IOCTL.
+// That device would in turn need to have a secure companion driver (trustlet)
+// installed as part of the package to process the buffer.
+//
+HRESULT CInPin::ForwardSecureBuffer(
+ _In_ IMFSample *sample
+)
+{
+ DWORD bytesReturned = 0;
+ CONTOSODEVICE_PROCESSBUFFER_PAYLOAD payload = { 0 };
+ KSPROPERTY property = { 0 };
+
+ wil::com_ptr_nothrow<IMFMediaBuffer> mediaBuffer;
+ wil::com_ptr_nothrow<IMFSecureBuffer> secureBuffer;
+
+ // Set up our private KSPROPERTY to some sample avstream driver.
+ property.Set = PROPSETID_CONTOSODEVICE;
+ property.Id = KSPROPERTY_CONTOSODEVICE_PROCESSBUFFER;
+ property.Flags = KSPROPERTY_TYPE_SET;
+ // Set up the payload for that property. Includes the secure buffer ID and buffer length.
+ RETURN_IF_FAILED(sample->GetBufferByIndex(0, &mediaBuffer));
+ // Forward the buffer if it is secure.
+ if (mediaBuffer.try_query_to(&secureBuffer))
+ {
+ RETURN_IF_FAILED(secureBuffer->GetIdentifier(&payload.identifier));
+ RETURN_IF_FAILED(mediaBuffer->GetMaxLength(&payload.size));
+
+ // Log the buffer's secure ID and size for debugging.
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! identifier=%!GUID!, length=%d", &payload.identifier, payload.size);
+
+ // Send the KSPROPERTY synchronously to the driver.
+ RETURN_IF_FAILED(KsProperty(&property, sizeof(property), &payload, sizeof(payload), &bytesReturned));
+ }
+ return S_OK;
+}
+#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
//
//Output Pin Implementation
//
COutPin::COutPin(
_In_ ULONG ulPinId,
_In_opt_ CMultipinMft *pparent,
- _In_ IKsControl* pIksControl
+ _In_ IKsControl* pIksControl
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ , _In_ MFSampleAllocatorUsage allocatorUsage
+#endif
)
- : CBasePin( ulPinId, pparent ),
- m_firstSample( false ),
- m_queue(nullptr)
+ : CBasePin(ulPinId, pparent)
+ , m_firstSample(false)
+ , m_queue(nullptr)
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ , m_allocatorUsage(allocatorUsage)
+#endif
{
HRESULT hr = S_OK;
ComPtr<IMFAttributes> spAttributes;
@@ -507,6 +564,14 @@ STDMETHODIMP_(VOID) COutPin::SetFirstSample(
m_firstSample = fisrtSample;
}
+STDMETHODIMP_(VOID) COutPin::SetAllocator(
+ _In_ IMFVideoSampleAllocator* pAllocator
+)
+{
+ CAutoLock Lock(lock());
+ m_spDefaultAllocator = pAllocator;
+}
+
/*++
COutPin::FlushQueues
Description:
@@ -524,7 +589,7 @@ HRESULT COutPin::FlushQueues()
/*++
COutPin::ChangeMediaTypeFromInpin
Description:
-called from the Device Transfrom When the input media type is changed. This will result in
+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
--*/
@@ -542,7 +607,11 @@ HRESULT COutPin::ChangeMediaTypeFromInpin(
SetState(DeviceStreamState_Disabled);
DMFTCHECKHR_GOTO(FlushQueues(),done);
DMFTCHECKNULL_GOTO(m_queue,done, E_UNEXPECTED); // The queue should alwaye be set
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ hr = m_queue->RecreateTeeByAllocatorMode(pInMediatype, pOutMediaType, m_spDxgiManager.Get(), m_allocatorUsage, m_spDefaultAllocator.get());
+#else
hr = m_queue->RecreateTee(pInMediatype, pOutMediaType, m_spDxgiManager.Get());
+#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
if ( SUCCEEDED( hr ) )
{
(VOID)setMediaType( pOutMediaType );
@@ -583,10 +652,10 @@ STDMETHODIMP COutPin::GetOutputStreamInfo(
/*++
COutPin::ProcessOutput
Description:
- called from the Device Transfrom when the transform manager demands output samples..
+ 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 recieved the transform or not.
- If we have recieved the sample and we are passing out a sample we should reset the trigger set on the Device Transform
+ 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
--*/
STDMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags,
@@ -663,18 +732,9 @@ STDMETHODIMP CAsyncInPin::SendSample(_In_ IMFSample *pSample)
{
HRESULT hr = S_OK;
CAutoLock Lock(lock());
- if (!m_bFlushing)
+ if (SUCCEEDED(Active()))
{
DMFTCHECKHR_GOTO(MFPutWorkItem(m_dwWorkQueueId, static_cast<IMFAsyncCallback*>(m_asyncCallback.Get()), pSample), done);
- if (1 == InterlockedIncrement(&m_dwSamplesInFlight))
- {
- ResetEvent(m_hHandle);
- }
- }
- else
- {
- DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! 0x%p Pin Flushing %d",this, streamId());
- // Let the sample fall through
}
done:
return hr;
@@ -682,18 +742,20 @@ done:
STDMETHODIMP CAsyncInPin::Init()
{
- m_asyncCallback = new (std::nothrow) CDMFTAsyncCallback<CAsyncInPin, &CAsyncInPin::Invoke>(this);
+ m_asyncCallback = new (std::nothrow) CDMFTAsyncCallback<CAsyncInPin, &CAsyncInPin::Invoke>(this, m_dwWorkQueueId);
if (!m_asyncCallback)
throw bad_alloc();
return S_OK;
}
+// Pass a secure frame buffer to our AVstream driver.
HRESULT CAsyncInPin::Invoke( _In_ IMFAsyncResult* pResult )
{
HRESULT hr = S_OK;
ComPtr<IUnknown> spUnknown;
ComPtr<IMFSample> spSample;
+ DMFTCHECKHR_GOTO(Active(), done);
DMFTCHECKNULL_GOTO(pResult, done, E_UNEXPECTED);
DMFTCHECKHR_GOTO(pResult->GetState(&spUnknown), done);
@@ -701,46 +763,26 @@ HRESULT CAsyncInPin::Invoke( _In_ IMFAsyncResult* pResult )
DMFTCHECKNULL_GOTO(spSample.Get(), done, E_INVALIDARG);
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ //
+ // Do secure buffer post-processing.
+ //
+ RETURN_IF_FAILED(ForwardSecureBuffer(spSample.Get()));
+#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
COutPin *poPin = static_cast<COutPin*>(m_outpin.Get());
DMFTCHECKHR_GOTO(poPin->AddSample(spSample.Get(), this), done);
-
- if (0 == InterlockedDecrement(&m_dwSamplesInFlight))
- {
- // No samples in flight.. Set the Event
- SetEvent(m_hHandle);
- }
-
done:
return hr;
}
-
-
-STDMETHODIMP CAsyncInPin::FlushQueues()
+STDMETHODIMP_(VOID) CAsyncInPin::ShutdownPin()
{
- HRESULT hr = S_OK;
- DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Entering ");
- // Flush in async mode else it is a NOOP
- {
- CAutoLock Lock(lock());
- if (m_bFlushing)
- {
- DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin %d Already Flushing ", streamId());
- goto done;
- }
- m_bFlushing = TRUE;
- }
- //
- // Wait for the IOs to drain
- //
- WaitForSingleObject(m_hHandle, INFINITE);
+ CAutoLock Lock(lock());
+ if (m_asyncCallback.Get())
{
- CAutoLock Lock(lock());
- m_bFlushing = FALSE;
+ (VOID)m_asyncCallback->Shutdown(); //Break reference with the parent
}
-done:
- DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
- return hr;
+ CInPin::ShutdownPin();
}
//
@@ -808,6 +850,7 @@ STDMETHODIMP CTranslateOutPin::AddMediaType(
done:
return hr;
}
+
STDMETHODIMP_(BOOL) CTranslateOutPin::IsMediaTypeSupported(
_In_ IMFMediaType *pMediaType,
_When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
@@ -824,9 +867,10 @@ STDMETHODIMP_(BOOL) CTranslateOutPin::IsMediaTypeSupported(
if (found != m_TranslatedMediaTypes.end())
{
+ ComPtr<IMFMediaType> spMediaType = (*found).second;
if (ppIMFMediaTypeFull)
{
- *ppIMFMediaTypeFull = (*found).second;
+ *ppIMFMediaTypeFull = spMediaType.Detach();
}
return true;
}
@@ -836,3 +880,24 @@ STDMETHODIMP_(BOOL) CTranslateOutPin::IsMediaTypeSupported(
return CBasePin::IsMediaTypeSupported(pMediaType,ppIMFMediaTypeFull);
}
}
+
+HRESULT CTranslateOutPin::ChangeMediaTypeFromInpin(
+ _In_ IMFMediaType *pInMediatype,
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state)
+{
+ 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);
+ RETURN_IF_FAILED(FlushQueues());
+ RETURN_HR_IF_NULL(E_UNEXPECTED, m_queue); // The queue should always be set
+ RETURN_IF_FAILED(m_queue->RecreateTee(pInMediatype, pOutMediaType, m_spDxgiManager.Get()));
+
+ (VOID)setMediaType(pOutMediaType);
+ (VOID)SetState(state);
+
+ return S_OK;
+}
diff --git a/avstream/sampledevicemft/basepin.h b/avstream/sampledevicemft/basepin.h
index faafd759..cce17d0b 100644
--- a/avstream/sampledevicemft/basepin.h
+++ b/avstream/sampledevicemft/basepin.h
@@ -369,7 +369,7 @@ public:
__requires_lock_held(m_lock)
__inline HRESULT Active()
{
- return (m_state == DeviceStreamState_Run)?S_OK:E_FAIL;
+ return (m_state == DeviceStreamState_Run)?S_OK:HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
}
__inline DWORD streamId()
{
@@ -511,7 +511,7 @@ public:
return m_preferredStreamState;
}
- void ReleaseConnectedPins();
+ STDMETHOD_( VOID, ShutdownPin)();
protected:
ComPtr<IMFTransform> m_spSourceTransform; /*Source Transform i.e. DevProxy*/
@@ -520,15 +520,27 @@ protected:
DeviceStreamState m_preferredStreamState;
ComPtr<IMFMediaType> m_spPrefferedMediaType;
HANDLE m_waitInputMediaTypeWaiter; /*Set when the input media type is changed*/
+
+ // Helper functions
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ HRESULT ForwardSecureBuffer(
+ _In_ IMFSample *sample
+ );
+#endif
};
class COutPin: public CBasePin{
public:
- COutPin( _In_ ULONG id = 0,
+ COutPin(
+ _In_ ULONG id = 0,
_In_opt_ CMultipinMft *pparent = NULL,
- _In_ IKsControl* iksControl=NULL);
+ _In_ IKsControl* iksControl=NULL
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ , _In_ MFSampleAllocatorUsage allocatorUsage = MFSampleAllocatorUsage_DoesNotAllocate
+#endif
+ );
~COutPin();
STDMETHODIMP FlushQueues();
STDMETHODIMP AddPin(
@@ -541,7 +553,7 @@ public:
STDMETHODIMP GetOutputStreamInfo(
_Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
);
- STDMETHODIMP ChangeMediaTypeFromInpin(
+ virtual STDMETHODIMP ChangeMediaTypeFromInpin(
_In_ IMFMediaType *pInMediatype,
_In_ IMFMediaType* pOutMediaType,
_In_ DeviceStreamState state );
@@ -560,6 +572,16 @@ public:
STDMETHODIMP_(VOID) SetFirstSample(
_In_ BOOL
);
+
+ STDMETHODIMP_(VOID) SetAllocator(
+ _In_ IMFVideoSampleAllocator* pAllocator
+ );
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ MFSampleAllocatorUsage GetSampleAllocatorUsage()
+ {
+ return m_allocatorUsage;
+ }
+#endif
UINT32 GetMediatypeCount()
{
return (UINT32)m_listOfMediaTypes.size();
@@ -568,13 +590,17 @@ public:
protected:
CPinQueue * m_queue; /* Queue where the sample will be stored*/
BOOL m_firstSample;
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ MFSampleAllocatorUsage m_allocatorUsage;
+#endif
+ wil::com_ptr_nothrow<IMFVideoSampleAllocator> m_spDefaultAllocator;
+
};
class CAsyncInPin: public CInPin {
public:
- STDMETHODIMP FlushQueues();
STDMETHODIMP SendSample(
_In_ IMFSample *
);
@@ -587,30 +613,19 @@ public:
_In_ ULONG ulPinId,
_In_ CMultipinMft *pParent) : CInPin(pAttributes,
ulPinId, pParent)
- , m_dwSamplesInFlight(0)
- , m_hHandle(INVALID_HANDLE_VALUE)
- , m_bFlushing(FALSE)
, m_asyncCallback(nullptr)
{
- m_hHandle = CreateEvent(NULL, TRUE, TRUE, L"Async_Pin Event");
- if (m_hHandle == nullptr)
- throw bad_alloc();
Init();
-
}
+ STDMETHOD_(VOID, ShutdownPin)();
~CAsyncInPin()
{
FlushQueues();
- CloseHandle(m_hHandle);
- m_hHandle = INVALID_HANDLE_VALUE;
}
ComPtr<CDMFTAsyncCallback<CAsyncInPin,&CAsyncInPin::Invoke> > m_asyncCallback; // Callback object
- HANDLE m_hHandle; // Handles to keep flush state
- DWORD m_dwSamplesInFlight; // Samples in flight i.e. waiting for the callback functions to be called
- BOOL m_bFlushing;
////////////////////////////////////////////////////////////////////////////////////////
// End of Asynchronous callback definitions
////////////////////////////////////////////////////////////////////////////////////////
@@ -628,7 +643,12 @@ class CTranslateOutPin : public COutPin {
public:
CTranslateOutPin(_In_ ULONG id = 0,
_In_opt_ CMultipinMft *pparent = NULL,
- _In_ IKsControl* iksControl = NULL) : COutPin(id, pparent, iksControl)
+ _In_ IKsControl* iksControl = NULL)
+ : COutPin(id, pparent, iksControl
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ , MFSampleAllocatorUsage_UsesCustomAllocator
+#endif
+ )
{
SetUINT32(MF_SD_VIDEO_SPHERICAL, TRUE);
}
@@ -639,8 +659,14 @@ public:
_In_ IMFMediaType *pMediaType,
_When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
IMFMediaType **ppIMFMediaTypeFull);
+ STDMETHOD(ChangeMediaTypeFromInpin)(
+ _In_ IMFMediaType *pInMediatype,
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state);
+
protected:
map<IMFMediaType*, IMFMediaType*> m_TranslatedMediaTypes;
};
+
diff --git a/avstream/sampledevicemft/common.h b/avstream/sampledevicemft/common.h
index 72242fa3..bc6bbf28 100644
--- a/avstream/sampledevicemft/common.h
+++ b/avstream/sampledevicemft/common.h
@@ -291,7 +291,7 @@ HRESULT ExceptionBoundary(Lambda&& lambda)
}
catch (...)
{
- return E_FAIL;
+ return E_UNEXPECTED;
}
}
@@ -581,7 +581,7 @@ public:
pcbBuffer);
if (dwHeightInPixels* abs(*plStride) > *pcbBuffer)
{
- hr = E_FAIL;
+ hr = E_UNEXPECTED;
}
} else if (m_sp2DBuffer)
{
@@ -652,6 +652,13 @@ HRESULT IsDXFormatSupported(
_Outptr_opt_ ID3D11Device** ppDevice,
_In_opt_ PUINT32 pSupportedFormat);
+HRESULT ConfigureAllocator(
+ _In_ IMFMediaType* pOutputMediaType,
+ _In_ GUID streamCategory,
+ _In_ IUnknown* pDeviceManagerUnk,
+ _In_ BOOL &isDxAllocator,
+ _In_ IMFVideoSampleAllocator* pAllocator);
+
HRESULT CreateAllocator( _In_ IMFMediaType* pOutputMediaType,
_In_ GUID streamCategory,
_In_ IUnknown* pDeviceManagerUnk,
diff --git a/avstream/sampledevicemft/contosodevice.h b/avstream/sampledevicemft/contosodevice.h
new file mode 100644
index 00000000..66759f69
--- /dev/null
+++ b/avstream/sampledevicemft/contosodevice.h
@@ -0,0 +1,28 @@
+// 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.
+//
+// The Contoso device comes with an SDK
+// that defines various Contoso-specific types,
+// all of which have CONTOSO in their names.
+
+#pragma once
+
+// This payload is used when sending a KSPROPERTY_CONTOSODEVICE_PROCESSBUFFER.
+struct CONTOSODEVICE_PROCESSBUFFER_PAYLOAD
+{
+ GUID identifier;
+ DWORD size;
+};
+
+// Define a custom property set for driver communications.
+// {C5175EE2-583E-43A2-8C26-765287BCEB9D}
+#define STATIC_PROPSETID_CONTOSODEVICE\
+ 0xc5175ee2, 0x583e, 0x43a2, 0x8c, 0x26, 0x76, 0x52, 0x87, 0xbc, 0xeb, 0x9d
+DEFINE_GUIDSTRUCT("C5175EE2-583E-43A2-8C26-765287BCEB9D", PROPSETID_CONTOSODEVICE);
+#define PROPSETID_CONTOSODEVICE DEFINE_GUIDNAMED(PROPSETID_CONTOSODEVICE)
+#define KSPROPERTY_CONTOSODEVICE_PROCESSBUFFER 0 // Send a frame buffer ID to the driver.
+
diff --git a/avstream/sampledevicemft/custompin.cpp b/avstream/sampledevicemft/custompin.cpp
index 00edb329..edb5fadb 100644
--- a/avstream/sampledevicemft/custompin.cpp
+++ b/avstream/sampledevicemft/custompin.cpp
@@ -35,7 +35,7 @@ STDMETHODIMP CCustomPin::SendSample(
// Log sample and exit.. The pipeline will just keep on churning more samples till
// We go into the stop state
//
- DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin %d recieved Sample %p", streamId(), pSample);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin %d received Sample %p", streamId(), pSample);
return S_OK;
}
diff --git a/avstream/sampledevicemft/dllmain.cpp b/avstream/sampledevicemft/dllmain.cpp
index 6978a9d5..88bfe6ab 100644
--- a/avstream/sampledevicemft/dllmain.cpp
+++ b/avstream/sampledevicemft/dllmain.cpp
@@ -196,13 +196,35 @@ STDMETHODIMP_(BOOL) WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
DisableThreadLibraryCalls(hInstance);
#ifdef MF_WPP
WPP_INIT_TRACING(L"MultiPinMft");
+
+ // Hook up WIL tracing to our trace provider.
+ wil::SetResultLoggingCallback(
+ [](const wil::FailureInfo &failure)
+ {
+ wchar_t debugString[2048];
+ if (SUCCEEDED(wil::GetFailureLogString(debugString, ARRAYSIZE(debugString), failure)))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, L"%S", debugString);
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR,
+ L"File: %s, Line: %u, Error: 0x%08X - %S\n",
+ failure.pszFile,
+ failure.uLineNumber,
+ failure.hr,
+ failure.pszMessage);
+ }
+ }
+ );
#endif
}
else
if (dwReason == DLL_PROCESS_DETACH)
{
#ifdef MF_WPP
- WPP_CLEANUP();
+ wil::SetResultLoggingCallback(nullptr);
+ WPP_CLEANUP();
#endif
}
return TRUE;
diff --git a/avstream/sampledevicemft/multipinmft.cpp b/avstream/sampledevicemft/multipinmft.cpp
index 3467870b..f4fe3d27 100644
--- a/avstream/sampledevicemft/multipinmft.cpp
+++ b/avstream/sampledevicemft/multipinmft.cpp
@@ -1322,6 +1322,54 @@ done:
}
#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<COutPin> outPin = GetOutPin(dwOutputStreamID);
+ RETURN_HR_IF_NULL(E_INVALIDARG, outPin);
+ RETURN_HR_IF_NULL(E_INVALIDARG, pAllocator);
+
+ wil::com_ptr_nothrow<IMFVideoSampleAllocator> 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<COutPin> 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
//
@@ -1513,7 +1561,7 @@ HRESULT CMultipinMft::BridgeInputPinOutputPin(
HRESULT hr = S_OK;
ULONG ulIndex = 0;
ULONG ulAddedMediaTypeCount = 0;
- ComPtr<IMFMediaType> pMediaType = nullptr;
+ ComPtr<IMFMediaType> spMediaType;
DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
@@ -1523,19 +1571,17 @@ HRESULT CMultipinMft::BridgeInputPinOutputPin(
// sure any pin advertised supports at least one media type. The pipeline doesn't
// like pins with no media types
//
- while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, &pMediaType )))
+ while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, spMediaType.ReleaseAndGetAddressOf() )))
{
GUID subType = GUID_NULL;
- DMFTCHECKHR_GOTO( pMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done );
+ DMFTCHECKHR_GOTO( spMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done );
{
- DMFTCHECKHR_GOTO(hr = poPin->AddMediaType(NULL, pMediaType.Get() ), done );
+ DMFTCHECKHR_GOTO(hr = poPin->AddMediaType(NULL, spMediaType.Get() ), done );
if (hr == S_OK)
{
ulAddedMediaTypeCount++;
}
}
-
- pMediaType = nullptr;
}
if (ulAddedMediaTypeCount == 0)
{
@@ -1679,7 +1725,7 @@ STDMETHODIMP CMultipinMft::Shutdown(
CInPin *pInPin = static_cast<CInPin *>(m_InPins[ulIndex]);
// Deref on the connected outpins to break reference loop
- pInPin->ReleaseConnectedPins();
+ (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++)
diff --git a/avstream/sampledevicemft/multipinmft.h b/avstream/sampledevicemft/multipinmft.h
index 080f4a7a..70367f1d 100644
--- a/avstream/sampledevicemft/multipinmft.h
+++ b/avstream/sampledevicemft/multipinmft.h
@@ -48,6 +48,9 @@ class CMultipinMft :
, public IMFGetService
#endif
, public CDMFTModuleLifeTimeManager
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ , public IMFSampleAllocatorControl
+#endif
{
friend class CPinCreationFactory;
public:
@@ -275,7 +278,22 @@ public:
}
#endif
-
+#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);
diff --git a/avstream/sampledevicemft/multipinmft.vcxproj b/avstream/sampledevicemft/multipinmft.vcxproj
index 0f560e2c..1a0716bb 100644
--- a/avstream/sampledevicemft/multipinmft.vcxproj
+++ b/avstream/sampledevicemft/multipinmft.vcxproj
@@ -262,9 +262,17 @@
<None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
<None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
<None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ <None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <Import Project="packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
+ </Target>
</Project> \ No newline at end of file
diff --git a/avstream/sampledevicemft/multipinmft.vcxproj.Filters b/avstream/sampledevicemft/multipinmft.vcxproj.Filters
index e06f675d..36af8e37 100644
--- a/avstream/sampledevicemft/multipinmft.vcxproj.Filters
+++ b/avstream/sampledevicemft/multipinmft.vcxproj.Filters
@@ -42,5 +42,6 @@
<None Include="Source.def">
<Filter>Source Files</Filter>
</None>
+ <None Include="packages.config" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/avstream/sampledevicemft/multipinmfthelpers.cpp b/avstream/sampledevicemft/multipinmfthelpers.cpp
index 904625ad..34cebe8b 100644
--- a/avstream/sampledevicemft/multipinmfthelpers.cpp
+++ b/avstream/sampledevicemft/multipinmfthelpers.cpp
@@ -16,8 +16,7 @@ class CMediaTypePrinter;
//
CPinQueue::CPinQueue( _In_ DWORD dwPinId ,
_In_ IMFDeviceTransform* pParent)
-: m_teer(0),
- m_dwInPinId(dwPinId),
+ :m_dwInPinId(dwPinId),
m_pTransform(pParent),
m_cRef(1)
@@ -30,6 +29,7 @@ CPinQueue::CPinQueue( _In_ DWORD dwPinId ,
}
CPinQueue::~CPinQueue( )
{
+ Ctee::ReleaseTee(m_spTeer);
}
/*++
@@ -59,10 +59,10 @@ STDMETHODIMP_(VOID) CPinQueue::InsertInternal( _In_ IMFSample *pSample )
STDMETHODIMP 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 etc
+//m_spTeer is the wraptee.. this could be a null tee which is a passthrough, an xvp tee which inserts an xvp into the queue etc
//
{
- return m_teer->PassThrough( pSample );
+ return m_spTeer->PassThrough( pSample );
}
/*++
@@ -97,9 +97,9 @@ VOID CPinQueue::Clear( )
// Stop the tees
// Execute Flush
//
- if (m_teer)
+ if (m_spTeer)
{
- m_teer->Stop();
+ m_spTeer->Stop();
}
while ( !Empty() )
@@ -114,62 +114,99 @@ 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
+ 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,
+STDMETHODIMP CPinQueue::RecreateTee(_In_ IMFMediaType *inMediatype,
_In_ IMFMediaType *outMediatype,
- _In_opt_ IUnknown* punkManager )
+ _In_opt_ IUnknown* punkManager)
{
HRESULT hr = S_OK;
DMFT_conversion_type operation = DeviceMftTransformTypeIllegal;
-
- SAFE_DELETE(m_teer); // Should release the reference
- CNullTee *nulltee = new (std::nothrow) CNullTee(this);
- DMFTCHECKNULL_GOTO( nulltee, done, E_OUTOFMEMORY);
+ Ctee::ReleaseTee(m_spTeer);
+
+ ComPtr<CNullTee> spNulltee = new (std::nothrow) CNullTee(this);
+ DMFTCHECKNULL_GOTO(spNulltee.Get(), done, E_OUTOFMEMORY);
DMFTCHECKHR_GOTO(CompareMediaTypesForConverter(inMediatype, outMediatype, &operation), done);
if (operation == DeviceMftTransformTypeDecoder)
{
// Decoder needed
- CDecoderTee* pDecTee = new (std::nothrow) CDecoderTee(nulltee,
+ CDecoderTee* pDecTee = new (std::nothrow) CDecoderTee(spNulltee.Get(),
static_cast<CMultipinMft*>(m_pTransform)->GetQueueId(),
pinCategory());
DMFTCHECKNULL_GOTO(pDecTee, done, E_OUTOFMEMORY);
(void)pDecTee->SetD3DManager(punkManager);
- DMFTCHECKHR_GOTO(pDecTee->SetMediaTypes(inMediatype, outMediatype),done);
- m_teer = dynamic_cast<Ctee*>(pDecTee);
+ DMFTCHECKHR_GOTO(pDecTee->SetMediaTypes(inMediatype, outMediatype), done);
+ m_spTeer = pDecTee;
}
- else if (operation == DeviceMftTransformTypeXVP)
+ else if (operation == DeviceMftTransformTypeXVP)
{
- CXvptee* pXvptee = new (std::nothrow) CXvptee(nulltee, pinCategory());
+ CXvptee* pXvptee = new (std::nothrow) CXvptee(spNulltee.Get(), pinCategory());
DMFTCHECKNULL_GOTO(pXvptee, done, E_OUTOFMEMORY);
- (void)pXvptee->SetD3DManager( punkManager );
- DMFTCHECKHR_GOTO(pXvptee->SetMediaTypes( inMediatype, outMediatype ),done);
- m_teer = dynamic_cast< Ctee* >( pXvptee );
+ (void)pXvptee->SetD3DManager(punkManager);
+ DMFTCHECKHR_GOTO(pXvptee->SetMediaTypes(inMediatype, outMediatype), done);
+ m_spTeer = pXvptee;
}
else
{
- m_teer = nulltee; /*A simple passthrough*/
+ m_spTeer = spNulltee.Get(); /*A simple passthrough*/
}
done:
- DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
if (FAILED(hr))
{
- if (m_teer){
- delete(m_teer);
- m_teer = NULL;
+ Ctee::ReleaseTee(m_spTeer);
+ }
+ return hr;
+}
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+STDMETHODIMP CPinQueue::RecreateTeeByAllocatorMode(
+ _In_ IMFMediaType* inMediatype,
+ _In_ IMFMediaType* outMediatype,
+ _In_opt_ IUnknown* punkManager,
+ _In_ MFSampleAllocatorUsage allocatorUsage,
+ _In_opt_ IMFVideoSampleAllocator* pAllocator)
+{
+ HRESULT hr = S_OK;
+
+ Ctee::ReleaseTee(m_spTeer);// Should release the reference
+
+ wistd::unique_ptr<CNullTee> nulltee = wil::make_unique_nothrow<CNullTee>(this);
+ RETURN_IF_NULL_ALLOC(nulltee);
+
+ if (allocatorUsage == MFSampleAllocatorUsage_DoesNotAllocate)
+ {
+ m_spTeer.Attach(nulltee.release()); /*A simple passthrough*/
+ }
+ else
+ {
+ wistd::unique_ptr<CSampleCopytee> sampleCopytee;
+ RETURN_IF_NULL_ALLOC(sampleCopytee);
+ (void)sampleCopytee->SetD3DManager(punkManager);
+
+ if (allocatorUsage == MFSampleAllocatorUsage_UsesProvidedAllocator)
+ {
+ RETURN_HR_IF_NULL(E_INVALIDARG, pAllocator);
+ sampleCopytee = wil::make_unique_nothrow<CSampleCopytee>(nulltee.release(), pinCategory(), pAllocator);
+ }
+ else
+ {
+ sampleCopytee = wil::make_unique_nothrow<CSampleCopytee>(nulltee.release(), pinCategory(), nullptr);
}
+ RETURN_IF_FAILED(sampleCopytee->SetMediaTypes(inMediatype, outMediatype));
+ m_spTeer.Attach(sampleCopytee.release());
}
+
return hr;
}
-
+#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
#ifdef MF_DEVICEMFT_ADD_GRAYSCALER_
STDMETHODIMP CPinQueueWithGrayScale::RecreateTee( _In_ IMFMediaType *inMediatype,
_In_ IMFMediaType *outMediatype,
@@ -183,7 +220,7 @@ STDMETHODIMP CPinQueueWithGrayScale::RecreateTee( _In_ IMFMediaType *inMediatyp
DMFTCHECKHR_GOTO(CPinQueue::RecreateTee(inMediatype,
outMediatype,
punkManager),done);
- DMFTCHECKNULL_GOTO(m_teer, done, E_UNEXPECTED);
+ DMFTCHECKNULL_GOTO(m_spTeer, done, E_UNEXPECTED);
// Wrap the media type with Gray scale tee only if the input media type is a YUY2, UYVY, NV12 or RGB32
DMFTCHECKHR_GOTO(inMediatype->GetGUID(MF_MT_SUBTYPE, &gInputSubType), done);
if (IsEqualCLSID(gInputSubType, MFVideoFormat_NV12)
@@ -192,9 +229,9 @@ STDMETHODIMP CPinQueueWithGrayScale::RecreateTee( _In_ IMFMediaType *inMediatyp
||IsEqualCLSID(gInputSubType, MFVideoFormat_RGB32))
{
CGrayTee *pTee = NULL;
- pTee = new (std::nothrow) CGrayTee(m_teer);
+ pTee = new (std::nothrow) CGrayTee(m_spTeer);
DMFTCHECKHR_GOTO(pTee->SetMediaTypes(inMediatype, outMediatype), done);
- m_teer = dynamic_cast< Ctee* >(pTee);
+ m_spTeer = dynamic_cast< Ctee* >(pTee);
}
else
{
@@ -251,9 +288,9 @@ STDMETHODIMP CWrapTee::PassThrough( _In_ IMFSample* pInSample )
DMFTCHECKNULL_GOTO(pInSample, done, S_OK); // pass through for no sample
DMFTCHECKHR_GOTO(Do(pInSample, &pOutSample,newSample),done);
- if (m_objectWrapped)
+ if (m_spObjectWrapped)
{
- if (SUCCEEDED(hr = m_objectWrapped->PassThrough( pOutSample )))
+ if (SUCCEEDED(hr = m_spObjectWrapped->PassThrough( pOutSample )))
{
//@@@@README There is a very bad bug in the pipeline that the device transform manager
// is not releasing the reference on the sample when it is passed to the device MFT so any
@@ -289,7 +326,7 @@ HRESULT CVideoProcTee::SetMediaTypes(_In_ IMFMediaType* pInMediaType, _In_ IMFMe
ComPtr<IMFTransform> spTransform;
DMFTCHECKHR_GOTO(CWrapTee::SetMediaTypes(pInMediaType, pOutMediaType),done);
DMFTCHECKHR_GOTO(Configure(pInMediaType, pOutMediaType, spTransform.GetAddressOf()), done);
- m_videoProcessor = spTransform.Detach();
+ m_spVideoProcessor = spTransform.Detach();
//
// Start streaming
//
@@ -298,6 +335,8 @@ done:
return hr;
}
+
+
HRESULT CVideoProcTee::CreateAllocator()
{
HRESULT hr = S_OK;
@@ -307,18 +346,37 @@ HRESULT CVideoProcTee::CreateAllocator()
return S_OK;
}
- if (m_spAllocator.Get())
+ if (m_spPrivateAllocator)
{
// Release what we have currently
- DMFTCHECKHR_GOTO(m_spAllocator->UninitializeSampleAllocator(), done);
- m_spAllocator = nullptr;
+ RETURN_IF_FAILED(m_spPrivateAllocator->UninitializeSampleAllocator());
+ m_spPrivateAllocator = nullptr;
+ }
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ if (m_spDefaultAllocator)
+ {
+ // Configure default allocator
+ m_spDefaultAllocator->UninitializeSampleAllocator();
+ RETURN_IF_FAILED(::ConfigureAllocator(
+ m_pOutputMediaType.Get(),
+ m_streamCategory,
+ m_spDeviceManagerUnk.Get(),
+ m_fSetD3DManager,
+ m_spDefaultAllocator.Get()));
+ }
+ else
+#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ {
+ // Create and configure private allocator
+ RETURN_IF_FAILED(MFCreateVideoSampleAllocatorEx(IID_PPV_ARGS(m_spPrivateAllocator.ReleaseAndGetAddressOf())));
+ RETURN_IF_FAILED(::ConfigureAllocator(
+ m_pOutputMediaType.Get(),
+ m_streamCategory,
+ m_spDeviceManagerUnk.Get(),
+ m_fSetD3DManager,
+ m_spPrivateAllocator.Get()));
}
- DMFTCHECKHR_GOTO(::CreateAllocator(m_pOutputMediaType.Get(),
- m_streamCategory, m_spDeviceManagerUnk.Get(),
- m_fSetD3DManager,
- m_spAllocator.GetAddressOf()), done);
-done:
return hr;
}
@@ -342,6 +400,7 @@ CXvptee::~CXvptee()
HRESULT CXvptee::StartStreaming()
{
HRESULT hr = S_OK;
+ CAutoLock Lock(m_Lock);
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
done:
@@ -351,6 +410,8 @@ done:
HRESULT CXvptee::StopStreaming()
{
HRESULT hr = S_OK;
+ CAutoLock Lock(m_Lock);
+ SetAsyncStatus(MF_E_SHUTDOWN);
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
@@ -374,17 +435,17 @@ STDMETHODIMP CXvptee::Do(_In_ IMFSample *pSample, _Outptr_ IMFSample** ppOutSamp
MFT_OUTPUT_DATA_BUFFER outputSample;
ComPtr <IMFSample> spXVPOutputSample;
DWORD dwStatus = 0;
+ CAutoLock Lock(m_Lock);
DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP ProcessOutput Processing Sample =%p", pSample);
DMFTCHECKNULL_GOTO(ppOutSample, done, E_INVALIDARG);
-
*ppOutSample = nullptr;
-
+ DMFTCHECKHR_GOTO(GetAsyncStatus(), done);
DMFTCHECKHR_GOTO(Transform()->MFTProcessInput(0, pSample, 0),done);
outputSample.dwStreamID = 0;
outputSample.pSample = NULL;
- DMFTCHECKHR_GOTO(m_spAllocator->AllocateSample(&outputSample.pSample), done);
+ DMFTCHECKHR_GOTO(m_spPrivateAllocator->AllocateSample(&outputSample.pSample), done);
hr = Transform()->MFTProcessOutput(0, 1, &outputSample, &dwStatus);
@@ -492,16 +553,18 @@ done:
CDecoderTee::~CDecoderTee()
{
(VOID)StopStreaming();
- if (m_spAllocator)
+ MFUnlockWorkQueue(m_dwCameraStreamWorkQueueId);
+ if (m_spPrivateAllocator)
{
- m_spAllocator->UninitializeSampleAllocator();
- m_spAllocator = nullptr;
+ m_spPrivateAllocator->UninitializeSampleAllocator();
+ m_spPrivateAllocator = nullptr;
}
}
HRESULT CDecoderTee::StartStreaming()
{
HRESULT hr = S_OK;
+ CAutoLock Lock(&m_Lock);
DMFTCHECKNULL_GOTO(Transform(), done, MF_E_UNEXPECTED);
DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), done);
DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), done);
@@ -512,13 +575,11 @@ HRESULT CDecoderTee::StartStreaming()
HRESULT CDecoderTee::StopStreaming()
{
HRESULT hr = S_OK;
- ComPtr<IMFTransform> spTransform = Transform();
+ ComPtr<IMFTransform> spTransform;
{
- CAutoLock Lock(&m_critSec);
- if (m_hSyncHandle)
- {
- ResetEvent(m_hSyncHandle);
- }
+ CAutoLock Lock(&m_Lock);
+ spTransform = Transform();
+ SetAsyncStatus(MF_E_SHUTDOWN);
}
if (spTransform.Get())
{
@@ -531,15 +592,7 @@ HRESULT CDecoderTee::StopStreaming()
{
(void)spShutdown->Shutdown();
}
- m_critSec.Lock();
- SetAsyncStatus(MF_E_SHUTDOWN);
- MFUnlockWorkQueue(m_dwCameraStreamWorkQueueId);
- if (m_ulProcessOutputsInFlight > 0)
- {
- m_critSec.Unlock();
- WaitForSingleObject(m_hSyncHandle, INFINITE);
-
- }
+
spTransform = nullptr;
}
done:
@@ -553,17 +606,12 @@ STDMETHODIMP CDecoderTee::Configure(_In_opt_ IMFMediaType *inType,
HRESULT hr = S_OK;
ComPtr<IMFTransform> spTransform;
GUID gInSubType = GUID_NULL, gOutSubType = GUID_NULL;
+
DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG);
DMFTCHECKNULL_GOTO(inType, done, E_INVALIDARG);
DMFTCHECKNULL_GOTO(outType, done, E_INVALIDARG);
*ppTransform = nullptr;
- SAFE_CLOSEHANDLE(m_hSyncHandle);
- m_hSyncHandle = CreateEvent(NULL,
- FALSE,
- TRUE,
- TEXT("SyncDecoderWaiter")
- );
if (!(SUCCEEDED(inType->GetGUID(MF_MT_SUBTYPE, &gInSubType))
&& SUCCEEDED(outType->GetGUID(MF_MT_SUBTYPE, &gOutSubType))))
{
@@ -592,11 +640,6 @@ STDMETHODIMP CDecoderTee::Configure(_In_opt_ IMFMediaType *inType,
}
DMFTCHECKNULL_GOTO(spTransform.Get(), done, E_UNEXPECTED);
- if (m_D3daware && SUCCEEDED(IsDXFormatSupported(reinterpret_cast<IMFDXGIDeviceManager*>(m_spDeviceManagerUnk.Get()), gOutSubType, nullptr, nullptr)))
- {
- DMFTCHECKHR_GOTO(spTransform->MFTProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)m_spDeviceManagerUnk.Get()), done);
- }
-
DMFTCHECKHR_GOTO(spTransform->MFTGetOutputStreamInfo(m_dwMFTOutputId, &outputStreamInfo), done);
m_bProducesSamples = (outputStreamInfo.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES));
@@ -608,7 +651,7 @@ STDMETHODIMP CDecoderTee::Configure(_In_opt_ IMFMediaType *inType,
}
// Create a callback for processoutputs to be called on
- m_asyncCallback = new (std::nothrow) CDMFTAsyncCallback<CDecoderTee, &CDecoderTee::Invoke>(this);
+ m_asyncCallback = new (std::nothrow) CDMFTAsyncCallback<CDecoderTee, &CDecoderTee::Invoke>(this, m_dwQueueId);
DMFTCHECKNULL_GOTO(m_asyncCallback.Get(), done, E_OUTOFMEMORY);
if (m_fAsyncMFT)
@@ -636,9 +679,10 @@ STDMETHODIMP CDecoderTee::Do(_In_ IMFSample* pSample, _Outptr_ IMFSample **ppout
{
HRESULT hr = S_OK;
ComPtr<IMFSample> spOutputSample;
+ CAutoLock lock(m_Lock);
ComPtr<IMFTransform> spTransform = Transform();
+
newSample = false;
- CAutoLock lock(m_critSec);
DMFTCHECKNULL_GOTO(ppoutSample, done, E_INVALIDARG);
*ppoutSample = nullptr;
DMFTCHECKHR_GOTO(GetAsyncStatus(), done);
@@ -663,7 +707,6 @@ STDMETHODIMP CDecoderTee::Do(_In_ IMFSample* pSample, _Outptr_ IMFSample **ppout
spInputSample.Detach();
hr = S_OK;
// Queue a work item for process output
- m_ulProcessOutputsInFlight++;
DMFTCHECKHR_GOTO(MFPutWorkItem(m_dwCameraStreamWorkQueueId, m_asyncCallback.Get(), nullptr), done);
break;
}
@@ -720,7 +763,7 @@ HRESULT CDecoderTee::Invoke(_In_ IMFAsyncResult* pResult)
ComPtr<IMFTransform> spDecoderTemp;
ComPtr<IMFSample> spOutputSample;
BOOL bSendSample = FALSE;
- CAutoLock lock(m_critSec);
+ CAutoLock lock(m_Lock);
spDecoderTemp = Transform();
@@ -748,12 +791,12 @@ HRESULT CDecoderTee::Invoke(_In_ IMFAsyncResult* pResult)
case METransformHaveOutput:
{
ComPtr<IMFSample> spDecodedSample;
- m_critSec.Unlock();
+ m_Lock.Unlock();
//
// The processoutput call blocks for H264 sometimes. This call back is serialized
//
hr = ProcessOutputSync(spDecodedSample.GetAddressOf());
- m_critSec.Lock();
+ m_Lock.Lock();
// Did we error out when we released the lock?
DMFTCHECKHR_GOTO(GetAsyncStatus(), done);
if (SUCCEEDED(hr))
@@ -780,13 +823,12 @@ HRESULT CDecoderTee::Invoke(_In_ IMFAsyncResult* pResult)
{
// Synchronous mode. We only need it for processoutputs
ComPtr<IMFSample> spDecodedSample;
- m_ulProcessOutputsInFlight--;
DMFTCHECKHR_GOTO(GetAsyncStatus(), done);
DMFTCHECKNULL_GOTO(pResult, done, E_UNEXPECTED);
DMFTCHECKHR_GOTO(pResult->GetStatus(), done);
- m_critSec.Unlock();
+ m_Lock.Unlock();
hr = ProcessOutputSync(spDecodedSample.GetAddressOf());
- m_critSec.Lock();
+ m_Lock.Lock();
if (SUCCEEDED(hr))
{
// send the sample on its way
@@ -805,9 +847,9 @@ done:
if (bSendSample && spOutputSample.Get())
{
- if (m_objectWrapped)
+ if (m_spObjectWrapped)
{
- hr = m_objectWrapped->PassThrough(spOutputSample.Get());
+ hr = m_spObjectWrapped->PassThrough(spOutputSample.Get());
spOutputSample = nullptr;
}
}
@@ -823,11 +865,6 @@ done:
{
SetAsyncStatus(hr);
}
- if (m_StoppedAndWaiting)
- {
- // Stop is waiting on the threads to run
- SetEvent(m_hSyncHandle);
- }
return hr;
}
@@ -836,11 +873,11 @@ done:
// is holding on to the buffers, could be the xvp then this function will error
// out the pipeline. you should see the ALLOCATOR_E_EMPTY error pop up
//
-_Ret_maybenull_ HRESULT CDecoderTee::GetSample( IMFSample** ppSample )
+HRESULT CDecoderTee::GetSample( IMFSample** ppSample )
{
- if (!m_bProducesSamples && m_spAllocator.Get())
+ if (!m_bProducesSamples && m_spPrivateAllocator.Get())
{
- return m_spAllocator->AllocateSample(ppSample);
+ return m_spPrivateAllocator->AllocateSample(ppSample);
}
return S_OK;
}
@@ -890,7 +927,7 @@ HRESULT CDecoderTee::ProcessFormatChange()
// Also note, The platform doesn't support dynamic media type changes from the stream coming from the
// source.
//
- ComPtr<IMFTransform> spXvp;
+ ComPtr<CXvptee> spXvpTee;
DMFTCHECKHR_GOTO(m_pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &guidPreviousSubType), done);
for (DWORD i = 0; ; i++)
@@ -918,11 +955,11 @@ HRESULT CDecoderTee::ProcessFormatChange()
//
// Create the XVP and insert it into the chain manually. set the output to the mediatype requested by the platform
//
- CXvptee* pXvpTee = new (std::nothrow) CXvptee(m_objectWrapped ,m_streamCategory);
- DMFTCHECKNULL_GOTO(pXvpTee, done, E_OUTOFMEMORY);
- (VOID)pXvpTee->SetD3DManager(m_spDeviceManagerUnk.Get());
- DMFTCHECKHR_GOTO(pXvpTee->SetMediaTypes(spDecoderOutputMediaType.Get(), m_pOutputMediaType.Get()), done);
- m_objectWrapped = pXvpTee;
+ spXvpTee = new (std::nothrow) CXvptee(m_spObjectWrapped.Get() ,m_streamCategory);
+ DMFTCHECKNULL_GOTO(spXvpTee.Get(), done, E_OUTOFMEMORY);
+ (VOID)spXvpTee->SetD3DManager(m_spDeviceManagerUnk.Get());
+ DMFTCHECKHR_GOTO(spXvpTee->SetMediaTypes(spDecoderOutputMediaType.Get(), m_pOutputMediaType.Get()), done);
+ m_spObjectWrapped = spXvpTee;
spDecoderOutputMediaType = nullptr;
@@ -946,6 +983,7 @@ HRESULT CDecoderTee::ConfigDecoder(_In_ IMFTransform* pTransform, _In_ GUID guid
GUID guidMajorType;
GUID guidSubtype;
DWORD dwMediaTypeIndex = 0;
+ ComPtr<IMFDXGIDeviceManager> spDxgiManager;
UNREFERENCED_PARAMETER(guidSubType);
DMFTCHECKNULL_GOTO(pTransform, done, E_INVALIDARG);
@@ -973,12 +1011,22 @@ HRESULT CDecoderTee::ConfigDecoder(_In_ IMFTransform* pTransform, _In_ GUID guid
(void)ConfigRealTimeMFT(pTransform);
(void)pTransform->MFTGetStreamIDs(1, &m_dwMFTInputId, 1, &m_dwMFTOutputId);
- // Try to set input mediatype on MJPG decoder.
+ DMFTCHECKHR_GOTO(m_pOutputMediaType->GetMajorType(&guidMajorType), done);
+ DMFTCHECKHR_GOTO(m_pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubtype), done);
+
+ if (m_spDeviceManagerUnk.Get())
+ {
+ DMFTCHECKHR_GOTO(m_spDeviceManagerUnk.As(&spDxgiManager), done);
+ if (m_D3daware && SUCCEEDED(IsDXFormatSupported(spDxgiManager.Get(), guidSubtype, nullptr, nullptr)))
+ {
+ // Set the DXGI Manager here, before the input type is set
+ DMFTCHECKHR_GOTO(pTransform->MFTProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)m_spDeviceManagerUnk.Get()), done);
+ }
+ }
DMFTCHECKHR_GOTO(pTransform->MFTSetInputType(m_dwMFTInputId, m_pInputMediaType.Get(), 0), done);
// Find a matching output mediatype that has the same major/Subtype as pOutputType
- DMFTCHECKHR_GOTO(m_pOutputMediaType->GetMajorType(&guidMajorType), done);
- DMFTCHECKHR_GOTO(m_pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubtype), done);
+
while (SUCCEEDED(pTransform->MFTGetOutputAvailableType(m_dwMFTOutputId, dwMediaTypeIndex, &spMediaType)))
{
GUID guidMajorType2;
@@ -1061,6 +1109,18 @@ HRESULT CDecoderTee::ProcessOutputSync(_COM_Outptr_opt_ IMFSample** ppSample)
return hr;
}
+VOID CDecoderTee::ShutdownTee()
+{
+ CAutoLock lock(m_Lock);
+ SetAsyncStatus(MF_E_SHUTDOWN);
+ if (m_asyncCallback.Get())
+ {
+ // Break the circular reference between the
+ // internal async callback and the decoder
+ m_asyncCallback->Shutdown();
+ }
+}
+
#ifdef MF_DEVICEMFT_ADD_GRAYSCALER_
CGrayTee::CGrayTee(_In_ Ctee *tee) : CWrapTee(tee),m_transformfn(nullptr)
{
@@ -1174,6 +1234,122 @@ done:
}
#endif
+// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@//
+// @@@@ README: Sample copy related functions below
+//
+// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@//
+
+CSampleCopytee::CSampleCopytee(_In_ Ctee *tee, GUID category
+ , IMFVideoSampleAllocator* sampleAllocator
+) :
+ CVideoProcTee(tee, category
+ , sampleAllocator
+ )
+{
+
+}
+
+CSampleCopytee::~CSampleCopytee()
+{
+ (VOID)StopStreaming();
+ m_spDeviceManagerUnk = nullptr;
+}
+
+HRESULT CSampleCopytee::StartStreaming()
+{
+ CAutoLock lock(m_Lock);
+ RETURN_IF_FAILED(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0));
+ RETURN_IF_FAILED(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0));
+
+ return S_OK;
+}
+
+HRESULT CSampleCopytee::StopStreaming()
+{
+ CAutoLock lock(m_Lock);
+ SetAsyncStatus(MF_E_SHUTDOWN);
+ RETURN_IF_FAILED(Transform()->MFTProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0)); // Flush the stream
+ RETURN_IF_FAILED(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0)); // Notify end of stream
+ RETURN_IF_FAILED(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0)); // Notify end of streaming
+
+ return S_OK;
+}
+
+STDMETHODIMP CSampleCopytee::Do(_In_ IMFSample *pSample, _Outptr_ IMFSample** ppOutSample, _Inout_ bool &newSample)
+{
+
+ HRESULT hr = S_OK;
+ MFT_OUTPUT_DATA_BUFFER outputSample;
+ ComPtr <IMFSample> spXVPOutputSample;
+ DWORD dwStatus = 0;
+ CAutoLock lock(m_Lock);
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Processing Sample =%p", pSample);
+ RETURN_HR_IF_NULL(E_INVALIDARG, ppOutSample);
+
+ *ppOutSample = nullptr;
+ RETURN_IF_FAILED(GetAsyncStatus());
+ RETURN_IF_FAILED(Transform()->MFTProcessInput(0, pSample, 0));
+
+ outputSample.dwStreamID = 0;
+ outputSample.pSample = NULL;
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ if (m_spDefaultAllocator)
+ {
+ RETURN_IF_FAILED(m_spDefaultAllocator->AllocateSample(&outputSample.pSample));
+ }
+ else
+#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ {
+ RETURN_IF_FAILED(m_spPrivateAllocator->AllocateSample(&outputSample.pSample));
+ }
+
+
+ hr = Transform()->MFTProcessOutput(0, 1, &outputSample, &dwStatus);
+
+ if (SUCCEEDED(hr) && pSample)
+ {
+ spXVPOutputSample.Attach(outputSample.pSample);
+ }
+ else
+ {
+ SAFE_RELEASE(outputSample.pSample);
+ }
+
+ if (spXVPOutputSample.Get())
+ {
+ newSample = true;
+ *ppOutSample = spXVPOutputSample.Detach();
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CSampleCopytee::Configure(
+ _In_opt_ IMFMediaType* inMediaType,
+ _In_opt_ IMFMediaType* outMediaType,
+ _Outptr_ IMFTransform **ppTransform
+)
+{
+ RETURN_HR_IF_NULL(E_INVALIDARG, ppTransform);
+
+ 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());
+
+ RETURN_IF_FAILED(MFCreateSampleCopierMFT(ppTransform));
+ RETURN_IF_FAILED(CreateAllocator());
+
+ if (m_fSetD3DManager)
+ {
+ RETURN_IF_FAILED((*ppTransform)->MFTProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, reinterpret_cast<UINT_PTR>(m_spDeviceManagerUnk.Get())));
+ }
+
+ return S_OK;
+}
+
+
/*++
Descrtiption:
Handles events sent by the pipeline
@@ -1256,7 +1432,7 @@ HRESULT CDMFTEventHandler::KSEvent(
for (; it != m_RegularEventList.end(); it++)
{
PDMFTEventEntry pEntry = *it;
- DMFTCHECKNULL_GOTO(pEntry, done, E_FAIL);
+ DMFTCHECKNULL_GOTO(pEntry, done, E_UNEXPECTED);
if (pEntry->m_pEventData == pEventData)
{
break;
@@ -1547,7 +1723,11 @@ HRESULT CPinCreationFactory::CreatePin(_In_ ULONG ulInputStreamId, /* The Input
#if defined MF_DEVICEMFT_DECODING_MEDIATYPE_NEEDED
spOutPin = new (std::nothrow) CTranslateOutPin(ulOutStreamId, m_spDeviceTransform.Get(), spKscontrol.Get()); // Create the output pin
#else
- spOutPin = new (std::nothrow) COutPin(ulOutStreamId, m_spDeviceTransform.Get(), spKscontrol.Get()); // Create the output pin
+ spOutPin = new (std::nothrow) COutPin(ulOutStreamId, m_spDeviceTransform.Get(), spKscontrol.Get()
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ , MFSampleAllocatorUsage_DoesNotAllocate
+#endif
+ ); // Create the output pin
#endif
DMFTCHECKNULL_GOTO(spOutPin.Get(), done, E_OUTOFMEMORY);
@@ -1621,14 +1801,10 @@ done:
return hr;
}
-HRESULT CheckImagePin( _In_ IMFAttributes* pAttributes, _Out_ PBOOL pbIsImagePin )
+BOOL CheckImagePin( _In_ IMFAttributes* pAttributes, _Out_ PBOOL pbIsImagePin )
{
- if ((SUCCEEDED(CheckPinType(pAttributes, PINNAME_IMAGE, pbIsImagePin)) && pbIsImagePin) ||
- (SUCCEEDED(CheckPinType(pAttributes, PINNAME_VIDEO_STILL, pbIsImagePin)) && pbIsImagePin))
- {
- return S_OK;
- }
- return E_FAIL;
+ return ((SUCCEEDED(CheckPinType(pAttributes, PINNAME_IMAGE, pbIsImagePin)) && pbIsImagePin) ||
+ (SUCCEEDED(CheckPinType(pAttributes, PINNAME_VIDEO_STILL, pbIsImagePin)) && pbIsImagePin));
}
HRESULT CheckPreviewPin( _In_ IMFAttributes* pAttributes, _Out_ PBOOL pbIsPreviewPin)
diff --git a/avstream/sampledevicemft/multipinmfthelpers.h b/avstream/sampledevicemft/multipinmfthelpers.h
index bd3f0876..681ca071 100644
--- a/avstream/sampledevicemft/multipinmfthelpers.h
+++ b/avstream/sampledevicemft/multipinmfthelpers.h
@@ -32,9 +32,9 @@ template< typename T , HRESULT ( __stdcall T::*Func) ( IMFAsyncResult* ) >
class CDMFTAsyncCallback : public IMFAsyncCallback
{
public:
- CDMFTAsyncCallback( T* parent ) :
- m_cRef(1),
- m_Parent(parent)
+ CDMFTAsyncCallback( T* parent , DWORD dwWorkQueueId = MFASYNC_CALLBACK_QUEUE_STANDARD) :
+ m_Parent(parent),
+ m_dwQueueId(dwWorkQueueId)
{ }
virtual ~CDMFTAsyncCallback() { }
@@ -77,25 +77,40 @@ public:
STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
- // Implementation of this method is optional.
- UNREFERENCED_PARAMETER(pdwFlags);
- UNREFERENCED_PARAMETER(pdwQueue);
+ *pdwFlags = 0;
+ *pdwQueue = m_dwQueueId;
return E_NOTIMPL;
}
STDMETHODIMP Invoke( IMFAsyncResult* pAsyncResult )
{
- return (m_Parent->*Func)(pAsyncResult);
+ ComPtr<T> spParent;
+ {
+ // Take a reference on the parent so that
+ // shutdown may not yank it from us
+ CAutoLock Lock(&m_Lock);
+ spParent = m_Parent;
+ }
+ if (spParent.Get())
+ {
+ return ((spParent.Get())->*Func)(pAsyncResult);
+ }
+ return MF_E_SHUTDOWN;
+ }
+ VOID Shutdown()
+ {
+ CAutoLock Lock(&m_Lock);
+ m_Parent = nullptr; //Break the reference
}
- // TODO: Implement this method.
-
T GetParent()
{
return m_Parent;
}
protected:
- T* m_Parent; // Weak reference to the parent
- long m_cRef;
+ CCritSec m_Lock;
+ ComPtr<T> m_Parent;
+ long m_cRef = 0;
+ DWORD m_dwQueueId = MFASYNC_CALLBACK_QUEUE_STANDARD;
};
@@ -107,7 +122,18 @@ public:
STDMETHODIMP_(VOID) InsertInternal ( _In_ IMFSample *pSample = nullptr );
STDMETHODIMP Insert ( _In_ IMFSample *pSample );
STDMETHODIMP Remove (_Outptr_result_maybenull_ IMFSample **pSample);
- virtual STDMETHODIMP RecreateTee ( _In_ IMFMediaType *inMediatype, _In_ IMFMediaType *outMediatype, _In_opt_ IUnknown* punkManager );
+ virtual STDMETHODIMP RecreateTee (
+ _In_ IMFMediaType *inMediatype,
+ _In_ IMFMediaType *outMediatype,
+ _In_opt_ IUnknown* punkManager);
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ STDMETHODIMP RecreateTeeByAllocatorMode(
+ _In_ IMFMediaType* inMediatype,
+ _In_ IMFMediaType* outMediatype,
+ _In_opt_ IUnknown* punkManager,
+ _In_ MFSampleAllocatorUsage allocatorUsage,
+ _In_opt_ IMFVideoSampleAllocator* pAllcoator);
+#endif
STDMETHODIMP_(VOID) Clear();
//
@@ -179,7 +205,7 @@ private:
GUID m_streamCategory;
ULONG m_cRef;
protected:
- Ctee* m_teer; /*Tee that acts as a passthrough or an XVP */
+ ComPtr<Ctee> m_spTeer; /*Tee that acts as a passthrough or an XVP */
};
@@ -197,8 +223,20 @@ public:
// The below classes are used to add the
// XVP and the Decoder components.
//
-class Ctee{
+class Ctee: public IUnknown{
public:
+ // This is a helper class to release the interface
+ // It will first call shutdowntee to break any circular
+ // references any components might have with their composed
+ // objects
+ static VOID ReleaseTee( _In_ ComPtr<Ctee> &tee)
+ {
+ if (tee)
+ {
+ tee->ShutdownTee();
+ tee = nullptr;
+ }
+ }
STDMETHOD(Start)()
{
return S_OK;
@@ -208,35 +246,85 @@ public:
return S_OK;
}
virtual STDMETHODIMP PassThrough( _In_ IMFSample * ) = 0;
+
+ STDMETHOD_(VOID, ShutdownTee)()
+ {
+ return; // NOOP
+ }
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
+ {
+ HRESULT hr = S_OK;
+ if (ppv != nullptr)
+ {
+ *ppv = nullptr;
+ if (riid == __uuidof(IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown*>(this);
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+ }
+ else
+ {
+ hr = E_POINTER;
+ }
+ return hr;
+ }
+ Ctee()
+ {
+ }
+ virtual ~Ctee()
+ {}
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+ STDMETHODIMP_(ULONG) Release()
+ {
+ long cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0)
+ {
+ delete this;
+ }
+ return cRef;
+ }
+
+protected:
+ ULONG m_cRef = 0;
};
class CNullTee:public Ctee{
public:
- CNullTee(_In_ CPinQueue* q) :m_Queue(q) {}
+ CNullTee(_In_ CPinQueue* q)
+ : m_Queue(q)
+ {
+ }
STDMETHODIMP PassThrough( _In_ IMFSample* );
+
protected:
// Store the queue here for simplicity
ComPtr<CPinQueue> m_Queue;
};
-class CWrapTee : public Ctee{
+class CWrapTee : public Ctee
+{
public:
CWrapTee( _In_ Ctee *tee=nullptr )
-: m_objectWrapped(tee)
+ : m_spObjectWrapped(tee)
, m_pInputMediaType(nullptr)
, m_pOutputMediaType(nullptr)
{
}
- virtual ~CWrapTee()=0
+ virtual ~CWrapTee()
{
- if (m_objectWrapped)
- {
- delete(m_objectWrapped);
- }
}
+
STDMETHODIMP PassThrough ( _In_ IMFSample* );
virtual STDMETHODIMP Do ( _In_ IMFSample* pSample, _Out_ IMFSample ** , _Inout_ bool &newSample) = 0;
STDMETHODIMP SetMediaTypes(_In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType);
@@ -262,7 +350,7 @@ protected:
ComPtr< IMFMediaType > m_pInputMediaType;
ComPtr< IMFMediaType > m_pOutputMediaType;
- Ctee *m_objectWrapped;
+ ComPtr<Ctee> m_spObjectWrapped;
};
//
@@ -272,20 +360,26 @@ class CVideoProcTee: public CWrapTee
{
public:
- CVideoProcTee( _In_ Ctee* p, _In_ GUID category = PINNAME_PREVIEW ) :CWrapTee(p)
+ CVideoProcTee( _In_ Ctee* p, _In_ GUID category = PINNAME_PREVIEW
+ , _In_ IMFVideoSampleAllocator* sampleAllocator=nullptr
+ )
+ :CWrapTee(p)
, m_bProducesSamples(FALSE)
+ , m_asyncHresult(S_OK)
, m_streamCategory(category)
, m_fSetD3DManager(FALSE)
+ , m_spDefaultAllocator(sampleAllocator)
{}
__inline IMFTransform* Transform()
{
- return m_videoProcessor.Get();
+ return m_spVideoProcessor.Get();
}
VOID SetD3DManager( _In_opt_ IUnknown* pUnk )
{
- m_spDeviceManagerUnk = pUnk;
+ m_spDeviceManagerUnk = pUnk;
}
+
STDMETHODIMP SetMediaTypes(_In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType);
virtual STDMETHODIMP Configure(_In_ IMFMediaType *, _In_ IMFMediaType *, _Inout_ IMFTransform**) = 0;
STDMETHOD(CreateAllocator)();
@@ -294,19 +388,33 @@ public:
HRESULT hr = S_OK;
if (SUCCEEDED(hr = StopStreaming()))
{
- if (m_objectWrapped)
+ if (m_spObjectWrapped)
{
- hr = m_objectWrapped->Stop();
+ hr = m_spObjectWrapped->Stop();
}
}
return hr;
}
+ virtual ~CVideoProcTee()
+ {}
protected:
+ CCritSec m_Lock;
+ __inline VOID SetAsyncStatus(_In_ HRESULT hrStatus)
+ {
+ InterlockedCompareExchange(&m_asyncHresult, hrStatus, S_OK);
+ }
+ HRESULT GetAsyncStatus()
+ {
+ return InterlockedCompareExchange(&m_asyncHresult, S_OK, S_OK);
+ }
STDMETHOD(StartStreaming)() = 0;
STDMETHOD(StopStreaming)() = 0;
- ComPtr< IMFTransform > m_videoProcessor;
+ HRESULT m_asyncHresult;
+ ComPtr< IMFTransform > m_spVideoProcessor;
ComPtr<IUnknown> m_spDeviceManagerUnk;
- ComPtr<IMFVideoSampleAllocatorEx> m_spAllocator;
+ ComPtr<IMFVideoSampleAllocatorEx> m_spPrivateAllocator;
+ ComPtr<IMFVideoSampleAllocator> m_spDefaultAllocator;
+
BOOL m_bProducesSamples;
GUID m_streamCategory;
BOOL m_fSetD3DManager;
@@ -315,11 +423,12 @@ protected:
class CXvptee :public CVideoProcTee{
public:
CXvptee( _In_ Ctee *, _In_ GUID category = PINNAME_PREVIEW );
- ~CXvptee();
+ virtual ~CXvptee();
STDMETHOD(StartStreaming)();
STDMETHOD(StopStreaming)();
STDMETHODIMP Do ( _In_ IMFSample* pSample, _Outptr_ IMFSample **, _Inout_ bool &newSample);
STDMETHODIMP Configure ( _In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform** );
+
};
class CDecoderTee : public CVideoProcTee {
@@ -338,23 +447,11 @@ public:
, m_dwMFTInputId(0)
, m_dwMFTOutputId(0)
, m_dwQueueId(dwQueueId)
- ,m_dwCameraStreamWorkQueueId(0)
- , m_ulProcessOutputsInFlight(0)
- , m_hSyncHandle(INVALID_HANDLE_VALUE)
- , m_StoppedAndWaiting(FALSE)
+ , m_dwCameraStreamWorkQueueId(0)
{
m_streamCategory = category;
}
- ~CDecoderTee();
-
- __inline VOID SetAsyncStatus( _In_ HRESULT hrStatus )
- {
- InterlockedCompareExchange(&m_asyncHresult, hrStatus, S_OK);
- }
- HRESULT GetAsyncStatus()
- {
- return InterlockedCompareExchange(&m_asyncHresult, S_OK, S_OK);
- }
+ virtual ~CDecoderTee();
STDMETHODIMP Do(_In_ IMFSample* pSample, _Outptr_ IMFSample **, _Inout_ bool &newSample);
STDMETHODIMP Configure(_In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform**);
@@ -362,16 +459,17 @@ public:
protected:
STDMETHODIMP StartStreaming();
STDMETHODIMP StopStreaming();
- _Ret_maybenull_ HRESULT CDecoderTee::GetSample( _Outptr_ IMFSample**);
+ HRESULT GetSample( _Outptr_result_maybenull_ IMFSample**);
HRESULT ConfigDecoder( _In_ IMFTransform* ,_In_ GUID guidSubType = GUID_NULL);
HRESULT ConfigRealTimeMFT(_In_ IMFTransform* );
HRESULT ProcessOutputSync( _COM_Outptr_opt_ IMFSample** );
HRESULT ProcessFormatChange();
+ STDMETHOD_(VOID, ShutdownTee)();
BOOL m_fAsyncMFT;
BOOL m_D3daware;
BOOL m_hwMFT;
- ComPtr<CDMFTAsyncCallback<CDecoderTee,&CDecoderTee::Invoke> > m_asyncCallback;
+ ComPtr<CDMFTAsyncCallback<CDecoderTee, &CDecoderTee::Invoke> > m_asyncCallback;
HRESULT m_asyncHresult;
DWORD m_lNeedInputRequest;
GUID m_streamCategory; // Needed for bind flags
@@ -381,14 +479,22 @@ protected:
ComPtr<IMFSample> m_spUnprocessedSample;
DWORD m_dwQueueId;
DWORD m_dwCameraStreamWorkQueueId;
- CCritSec m_critSec;
std::deque<ComPtr<IMFSample> > m_InputSampleList;
- ULONG m_ulProcessOutputsInFlight;
- HANDLE m_hSyncHandle;
- BOOL m_StoppedAndWaiting;
};
+class CSampleCopytee :public CVideoProcTee {
+public:
+ CSampleCopytee(_In_ Ctee*, _In_ GUID category = PINNAME_PREVIEW
+ , _In_ IMFVideoSampleAllocator* sampleAllocator = nullptr
+ );
+ ~CSampleCopytee();
+ STDMETHOD(StartStreaming)();
+ STDMETHOD(StopStreaming)();
+ STDMETHODIMP Do(_In_ IMFSample* pSample, _Outptr_ IMFSample **, _Inout_ bool &newSample);
+ STDMETHODIMP Configure(_In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform**);
+};
+
#ifdef MF_DEVICEMFT_ADD_GRAYSCALER_
class CGrayTee : public CWrapTee {
public:
@@ -499,6 +605,7 @@ public:
DMFT_PIN_INPUT,
DMFT_PIN_OUTPUT,
DMFT_PIN_CUSTOM,
+ DMFT_PIN_ALLOCATOR_PIN,
DMFT_MAX
}type_pin;
HRESULT CreatePin( _In_ ULONG ulInputStreamId, _In_ ULONG ulOutStreamId, _In_ type_pin type,_Outptr_ CBasePin** ppPin, _In_ BOOL& isCustom);
@@ -506,7 +613,7 @@ public:
}
};
HRESULT CheckPinType(_In_ IMFAttributes* pAttributes, _In_ GUID pinType, _Out_ PBOOL pbIsImagePin);
-HRESULT CheckImagePin(_In_ IMFAttributes* pAttributes, _Out_ PBOOL pbIsImagePin);
+BOOL CheckImagePin(_In_ IMFAttributes* pAttributes, _Out_ PBOOL pbIsImagePin);
HRESULT CheckPreviewPin(_In_ IMFAttributes* pAttributes, _Out_ PBOOL pbIsPreviewPin);
diff --git a/avstream/sampledevicemft/multipinmftutils.cpp b/avstream/sampledevicemft/multipinmftutils.cpp
index d056b364..e4a62d52 100644
--- a/avstream/sampledevicemft/multipinmftutils.cpp
+++ b/avstream/sampledevicemft/multipinmftutils.cpp
@@ -1301,6 +1301,83 @@ done:
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<IMFVideoSampleAllocatorEx> spPrivateAllocator;
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ wil::com_ptr_nothrow<IMFVideoCaptureSampleAllocator> spDefaultAllocator;
+#endif
+ wil::com_ptr_nothrow<IMFAttributes> 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
@@ -1337,7 +1414,7 @@ HRESULT CreateAllocator( _In_ IMFMediaType* pOutputMediaType,
DMFTCHECKHR_GOTO(MFCreateAttributes(&spAllocatorAttributes, 8), done);
DMFTCHECKHR_GOTO(spAllocatorAttributes->SetUINT32(MF_SA_BUFFERS_PER_SAMPLE, 1), done);
- if (pDeviceManagerUnk != nullptr)
+ if (pDeviceManagerUnk != nullptr)
{
if (SUCCEEDED(UpdateAllocatorAttributes(spAllocatorAttributes.Get(), streamCategory,guidSubtype, (IMFDXGIDeviceManager*)pDeviceManagerUnk)))
{
@@ -1349,6 +1426,7 @@ HRESULT CreateAllocator( _In_ IMFMediaType* pOutputMediaType,
{
DMFTCHECKHR_GOTO(spVideoSampleAllocator->SetDirectXManager(pDeviceManagerUnk), done);
}
+
DMFTCHECKHR_GOTO(spVideoSampleAllocator->InitializeSampleAllocatorEx(ALLOCATOR_MIN_SAMPLES, ALLOCATOR_MAX_SAMPLES, spAllocatorAttributes.Get(), pOutputMediaType), done);
*ppAllocator = spVideoSampleAllocator.Detach();
@@ -1487,16 +1565,16 @@ done:
HRESULT MergeSampleAttributes( _In_ IMFSample* pInSample, _Inout_ IMFSample* pOutSample)
{
HRESULT hr = S_OK;
- DMFTCHECKNULL_GOTO(pInSample, done, E_INVALIDARG);
- DMFTCHECKNULL_GOTO(pOutSample, done, E_INVALIDARG);
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++)
{
diff --git a/avstream/sampledevicemft/packages.config b/avstream/sampledevicemft/packages.config
new file mode 100644
index 00000000..09cb1163
--- /dev/null
+++ b/avstream/sampledevicemft/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.190716.2" targetFramework="native" />
+</packages> \ No newline at end of file
diff --git a/avstream/sampledevicemft/stdafx.h b/avstream/sampledevicemft/stdafx.h
index e2f5a6cd..657208cd 100644
--- a/avstream/sampledevicemft/stdafx.h
+++ b/avstream/sampledevicemft/stdafx.h
@@ -41,6 +41,11 @@ using namespace std;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
+#include <wil\result.h>
+#include <wil\resource.h>
+#include <wil\com.h>
+#include <wil\result_macros.h>
+
// @@@@ README Please check / uncheck various hash defines to enable/ disable features
// MF_DEVICEMFT_ASYNCPIN_NEEDED will show how to use Asynchronous queues
// MF_DEVICEMFT_DECODING_MEDIATYPE_NEEDED will show how to decode a compressed mediatype.. it supports H264 and MJPG
@@ -49,7 +54,7 @@ using namespace Microsoft::WRL;
//
//#define MF_DEVICEMFT_ADD_GRAYSCALER_ 1
#define MF_DEVICEMFT_ASYNCPIN_NEEDED 1
-#define MF_DEVICEMFT_DECODING_MEDIATYPE_NEEDED 1
+//#define MF_DEVICEMFT_DECODING_MEDIATYPE_NEEDED 0
#define MF_DEVICEMFT_SET_SPHERICAL_ATTRIBUTES 1
//#define MF_DEVICEMFT_ENUM_HW_DECODERS 1