summaryrefslogtreecommitdiff
path: root/avstream/sampledevicemft/basepin.cpp
diff options
context:
space:
mode:
authorJitesh Krishnan <[email protected]>2018-07-10 16:38:00 -0700
committerJitesh Krishnan <[email protected]>2018-07-10 16:38:00 -0700
commit6e840ff0ff673ceff172b5732971f6242958603d (patch)
tree5eadce3cf3edd2074ec9d3a578ec8a4aa2ac3141 /avstream/sampledevicemft/basepin.cpp
parent6c1981b8504329521343ad00f32daa847fa6083a (diff)
changes to device MFT to include platform concepts like decoder/ XVP/ Work Queues/ Allocators
Diffstat (limited to 'avstream/sampledevicemft/basepin.cpp')
-rw-r--r--avstream/sampledevicemft/basepin.cpp241
1 files changed, 154 insertions, 87 deletions
diff --git a/avstream/sampledevicemft/basepin.cpp b/avstream/sampledevicemft/basepin.cpp
index 80647f39..d4220397 100644
--- a/avstream/sampledevicemft/basepin.cpp
+++ b/avstream/sampledevicemft/basepin.cpp
@@ -29,6 +29,7 @@ CBasePin::CBasePin( _In_ ULONG id, _In_ CMultipinMft *parent) :
, m_setMediaType(nullptr)
, m_nRefCount(0)
, m_state(DeviceStreamState_Stop)
+ , m_dwWorkQueueId(MFASYNC_CALLBACK_QUEUE_UNDEFINED)
{
}
@@ -59,6 +60,7 @@ HRESULT CBasePin::AddMediaType( _Inout_ DWORD *pos, _In_ IMFMediaType *pMediaTyp
{
HRESULT hr = S_OK;
CAutoLock Lock(lock());
+
DMFTCHECKNULL_GOTO(pMediaType, done, E_INVALIDARG);
hr = ExceptionBoundary([&]()
{
@@ -140,7 +142,6 @@ done:
return SUCCEEDED(hr) ? TRUE : FALSE;
}
-
STDMETHODIMP CBasePin::GetOutputAvailableType(
_In_ DWORD dwTypeIndex,
_Out_opt_ IMFMediaType** ppType)
@@ -148,7 +149,6 @@ STDMETHODIMP CBasePin::GetOutputAvailableType(
return GetMediaTypeAt( dwTypeIndex, ppType );
}
-
HRESULT CBasePin::QueryInterface(
_In_ REFIID iid,
_Outptr_result_maybenull_ void** ppv
@@ -179,10 +179,17 @@ HRESULT CBasePin::QueryInterface(
done:
return hr;
}
-
-
-
-
+VOID CBasePin::SetD3DManager(_In_opt_ IUnknown* pManager)
+{
+ //
+ // Should release the old dxgi manager.. We will not invalidate the pins or allocators
+ // We will recreate all allocator when the media types are set, so we should be fine
+ // And the pipeline will not set the dxgimanager when the pipeline is already built
+ //
+ CAutoLock Lock(lock());
+ m_spDxgiManager = pManager;
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting D3DManager on pin %d", m_StreamId);
+}
//
//Input Pin implementation
//
@@ -199,8 +206,6 @@ CInPin::CInPin(
setAttributes(pAttributes);
}
-
-
CInPin::~CInPin()
{
setAttributes( nullptr );
@@ -212,8 +217,6 @@ CInPin::~CInPin()
}
}
-
-
STDMETHODIMP CInPin::Init(
_In_ IMFTransform* pTransform
)
@@ -258,7 +261,6 @@ done:
return hr;
}
-
HRESULT CInPin::GenerateMFMediaTypeListFromDevice(
_In_ UINT uiStreamId
)
@@ -277,7 +279,7 @@ HRESULT CInPin::GenerateMFMediaTypeListFromDevice(
break;
DMFTCHECKHR_GOTO(AddMediaType(&pos, spMediaType.Get()), done);
- }
+ }
done:
if (hr == MF_E_NO_MORE_TYPES) {
hr = S_OK;
@@ -298,7 +300,7 @@ STDMETHODIMP CInPin::SendSample(
COutPin *poPin = static_cast<COutPin*>(m_outpin.Get());
DMFTCHECKNULL_GOTO(pSample, done, S_OK);
DMFTCHECKHR_GOTO(poPin->AddSample(pSample, this), done);
- DMFTCHECKHR_GOTO(Parent()->QueueEvent(METransformHaveOutput, GUID_NULL, S_OK, NULL),done);
+
done:
return hr;
}
@@ -312,7 +314,6 @@ STDMETHODIMP_(VOID) CInPin::ConnectPin( _In_ CBasePin * poPin )
}
}
-
STDMETHODIMP CInPin::WaitForSetInputPinMediaChange()
{
DWORD dwWait = 0;
@@ -385,6 +386,7 @@ HRESULT CInPin::SetInputStreamState(
void CInPin::ReleaseConnectedPins()
{
+ m_spSourceTransform = nullptr;
m_outpin = nullptr;
}
@@ -452,46 +454,15 @@ STDMETHODIMP COutPin::AddPin(
#if defined MF_DEVICEMFT_ADD_GRAYSCALER_ // Take this out to remove the gray scaler
m_queue = new (std::nothrow) CPinQueueWithGrayScale(inputPinId);
#else
- m_queue = new (std::nothrow) CPinQueue(inputPinId);
+ m_queue = new (std::nothrow) CPinQueue(inputPinId,Parent());
#endif
DMFTCHECKNULL_GOTO(m_queue, done, E_OUTOFMEMORY );
- //
- //Just ramdonmize media types for odd numbered pins
- //
- if ( streamId() != 0 && streamId() % 2 != 0 )
- {
- RandomnizeMediaTypes(m_listOfMediaTypes);
- }
-
done:
DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
return S_OK;
}
-
-/*++
-COutPin::AddSampleInternal
-Description:
-Called from AddSample if the Output Pin is in open state. This function looks for the queue
-corresponding to the input pin and adds it in the queue.
---*/
-
-STDMETHODIMP COutPin::AddSampleInternal(
- _In_ IMFSample *pSample,
- _In_ CBasePin *pPin )
-{
- HRESULT hr = S_OK;
- UNREFERENCED_PARAMETER(pPin);
- CAutoLock Lock( lock() );
- //
- // Add the sample into the queue. Add Ref the Sample
- //
- DMFTCHECKHR_GOTO(m_queue->Insert(pSample), done);
-done:
-return hr;
- }
-
/*++
COutPin::AddSample
Description:
@@ -504,15 +475,24 @@ STDMETHODIMP COutPin::AddSample(
_In_ CBasePin *pPin)
{
HRESULT hr = S_OK;
- CAutoLock lock( lock() );
+ UNREFERENCED_PARAMETER(pPin);
+
+ CAutoLock Lock(lock()); // Serialize
+
DMFTCHECKNULL_GOTO(pSample, done, E_INVALIDARG);
if (FAILED(Active()))
{
goto done;
}
- DMFTCHECKHR_GOTO( AddSampleInternal( pSample, pPin ),done );
-
+ DMFTCHECKHR_GOTO(m_queue->Insert(pSample), done);
done:
+ if (FAILED(hr))
+ {
+ // @@@@ Readme : This is how to throw error to the pipeline and inform it that there is an Error.
+ // This will destroy the pipeline and the App will need to recreate the source
+ //
+ DMFTCHECKHR_GOTO(Parent()->QueueEvent(MEError, GUID_NULL, hr, NULL), done);
+ }
return hr;
}
@@ -554,7 +534,6 @@ HRESULT COutPin::ChangeMediaTypeFromInpin(
_In_ DeviceStreamState state)
{
HRESULT hr = S_OK;
- ComPtr<IUnknown> spD3DManagerUnk = NULL;
CAutoLock Lock(lock());
//
//Set the state to disabled and while going out we will reset the state back to the requested state
@@ -563,8 +542,7 @@ HRESULT COutPin::ChangeMediaTypeFromInpin(
SetState(DeviceStreamState_Disabled);
DMFTCHECKHR_GOTO(FlushQueues(),done);
DMFTCHECKNULL_GOTO(m_queue,done, E_UNEXPECTED); // The queue should alwaye be set
- (VOID)Parent()->GetD3DDeviceManager(spD3DManagerUnk.GetAddressOf());
- hr = m_queue->RecreateTee( pInMediatype, pOutMediaType, spD3DManagerUnk.Get() );
+ hr = m_queue->RecreateTee(pInMediatype, pOutMediaType, m_spDxgiManager.Get());
if ( SUCCEEDED( hr ) )
{
(VOID)setMediaType( pOutMediaType );
@@ -585,7 +563,6 @@ STDMETHODIMP COutPin::GetOutputStreamInfo(
{
HRESULT hr = S_OK;
IMFMediaType* pMediatype = nullptr;
-
getMediaType( &pMediatype );
if (SUCCEEDED(hr) && !pMediatype) {
@@ -602,6 +579,7 @@ STDMETHODIMP COutPin::GetOutputStreamInfo(
return hr;
}
+
/*++
COutPin::ProcessOutput
Description:
@@ -619,19 +597,19 @@ STDMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags,
HRESULT hr = S_OK;
ComPtr<IMFSample> spSample;
MFTIME llTime = 0L;
-
UNREFERENCED_PARAMETER(pdwStatus);
UNREFERENCED_PARAMETER(dwFlags);
CAutoLock lock(lock());
-
+
if (FAILED(Active()))
{
goto done;
}
-
DMFTCHECKNULL_GOTO(m_queue, done, MF_E_INVALID_STREAM_STATE);
pOutputSample->dwStatus = S_OK;
+
DMFTCHECKHR_GOTO(m_queue->Remove(spSample.GetAddressOf()), done);
+
if (FAILED(spSample->GetSampleTime(&llTime)))
{
llTime = MFGetSystemTime();
@@ -644,9 +622,11 @@ STDMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags,
}
//
// Any processing before we pass the sample to further in the pipeline should be done here
- // PROCESSSAMPLE(pSample);
+ // PROCESSSAMPLE(pSample); There is a bug in the pipeline and to circumvent that we have to
+ // keep a reference on the sample. The pipeline is not releasing a reference when the sample
+ // is fed in ProcessInput. We are explicitly releasing it for the pipeline.
//
- pOutputSample->pSample = spSample.Get();
+ pOutputSample->pSample = spSample.Detach();
pOutputSample->dwStatus = S_OK;
done:
return hr;
@@ -685,16 +665,7 @@ STDMETHODIMP CAsyncInPin::SendSample(_In_ IMFSample *pSample)
CAutoLock Lock(lock());
if (!m_bFlushing)
{
- if (m_dwWorkQueueId == MFASYNC_CALLBACK_QUEUE_UNDEFINED)
- {
- //
- // Set the queue now
- // We will have the work queue id set before we start streaming
- //
- m_dwWorkQueueId = Parent()->GetQueueId();
- }
- DMFTCHECKHR_GOTO(MFPutWorkItem(m_dwWorkQueueId, &m_asyncCallback, pSample), done);
- pSample->AddRef();
+ DMFTCHECKHR_GOTO(MFPutWorkItem(m_dwWorkQueueId, static_cast<IMFAsyncCallback*>(m_asyncCallback.Get()), pSample), done);
if (1 == InterlockedIncrement(&m_dwSamplesInFlight))
{
ResetEvent(m_hHandle);
@@ -709,38 +680,42 @@ done:
return hr;
}
-STDMETHODIMP CAsyncInPin::SendSampleInternal(_In_ IMFSample *pSample)
+STDMETHODIMP CAsyncInPin::Init()
{
- HRESULT hr = S_OK;
- CAutoLock Lock(lock());
- DMFTCHECKNULL_GOTO(pSample, done, E_INVALIDARG);
- hr = CInPin::SendSample(pSample);
- pSample->Release();
- if (0 == InterlockedDecrement(&m_dwSamplesInFlight))
- {
- // No samples in flight.. Set the Event
- SetEvent(m_hHandle);
- }
-done:
- return hr;
+ m_asyncCallback = new (std::nothrow) CDMFTAsyncCallback<CAsyncInPin, &CAsyncInPin::Invoke>(this);
+ if (!m_asyncCallback)
+ throw bad_alloc();
+ return S_OK;
}
-STDMETHODIMP CAsyncInPin::CDMFTAsyncCallback::Invoke(_In_ IMFAsyncResult* pResult)
+
+HRESULT CAsyncInPin::Invoke( _In_ IMFAsyncResult* pResult )
{
HRESULT hr = S_OK;
ComPtr<IUnknown> spUnknown;
ComPtr<IMFSample> spSample;
+
DMFTCHECKNULL_GOTO(pResult, done, E_UNEXPECTED);
DMFTCHECKHR_GOTO(pResult->GetState(&spUnknown), done);
- DMFTCHECKHR_GOTO(spUnknown->QueryInterface(__uuidof(IUnknown), reinterpret_cast<PVOID*>(spSample.GetAddressOf())), done);
- CAsyncInPin *pPin = GetParent();
- DMFTCHECKNULL_GOTO(pPin, done, E_UNEXPECTED);
- DMFTCHECKHR_GOTO(pPin->SendSampleInternal(spSample.Get()), done);
+
+ DMFTCHECKHR_GOTO(spUnknown->QueryInterface(__uuidof(IMFSample), reinterpret_cast<PVOID*>(spSample.GetAddressOf())), done);
+
+ DMFTCHECKNULL_GOTO(spSample.Get(), done, E_INVALIDARG);
+
+ 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:
- DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
return hr;
}
+
STDMETHODIMP CAsyncInPin::FlushQueues()
{
HRESULT hr = S_OK;
@@ -768,4 +743,96 @@ done:
return hr;
}
+//
+// Pins that need translation like from MJPEG to NV12 or H264 to NV12
+// Return Value: S_OK: media type added, S_FALSE: mediatype skipped. Not an Error
+// Failure: any other catastrophic failure
+//
+STDMETHODIMP CTranslateOutPin::AddMediaType(
+ _Inout_ DWORD *pos,
+ _In_ IMFMediaType *pMediaType)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaType> pNewMediaType = nullptr;
+ GUID guidSubType = GUID_NULL;
+ auto needTranslation = [&](IMFMediaType* pMediaType) {
+ if (SUCCEEDED(pMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubType)))
+ {
+ for (UINT32 uiIndex = 0; uiIndex < ARRAYSIZE(tranlateGUIDS); uiIndex++)
+ {
+ if (IsEqualGUID(guidSubType, tranlateGUIDS[uiIndex]))
+ return true;
+ }
+ }
+ return false;
+ };
+ DMFTCHECKNULL_GOTO(pMediaType, done, E_INVALIDARG);
+ DMFTCHECKHR_GOTO(pMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubType), done);
+
+ // @@@@ README the below lines show how to exclude mediatypes which we don't want
+ /* if ((guidSubType != MFVideoFormat_H264))
+ {
+ hr = S_FALSE;
+ goto done;
+ }*/
+
+ if (needTranslation(pMediaType))
+ {
+ UINT32 uiWidth = 0, uiHeight = 0, uiImageSize = 0;
+
+ DMFTCHECKHR_GOTO(MFGetAttributeRatio(pMediaType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight), done);
+ DMFTCHECKHR_GOTO(MFCreateMediaType(pNewMediaType.GetAddressOf()), done);
+ DMFTCHECKHR_GOTO(pMediaType->CopyAllItems(pNewMediaType.Get()), done);
+ DMFTCHECKHR_GOTO(MFCalculateImageSize(translatedGUID, uiWidth, uiHeight, &uiImageSize), done);
+ DMFTCHECKHR_GOTO(pNewMediaType->SetGUID(MF_MT_SUBTYPE, translatedGUID), done);
+ DMFTCHECKHR_GOTO(pNewMediaType->SetUINT32(MF_MT_SAMPLE_SIZE, uiImageSize), done);
+ hr = ExceptionBoundary([&]()
+ {
+ m_TranslatedMediaTypes.insert(std::pair<IMFMediaType*, IMFMediaType*>( pNewMediaType.Get(), pMediaType));
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ else
+ {
+ pNewMediaType = pMediaType;
+ }
+ // Set custom properties here
+ //@@@@ README .. add these lines if you want this media types to be understood as a spherical media type
+#if defined MF_DEVICEMFT_SET_SPHERICAL_ATTRIBUTES
+ pNewMediaType->SetUINT32(MF_SD_VIDEO_SPHERICAL, TRUE);
+ pNewMediaType->SetUINT32(MF_SD_VIDEO_SPHERICAL_FORMAT, MFVideoSphericalFormat_Equirectangular);
+#endif
+ // Add it to the pin media type
+ hr = CBasePin::AddMediaType(pos, pNewMediaType.Get());
+done:
+ return hr;
+}
+STDMETHODIMP_(BOOL) CTranslateOutPin::IsMediaTypeSupported(
+ _In_ IMFMediaType *pMediaType,
+ _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
+ IMFMediaType **ppIMFMediaTypeFull)
+{
+ DWORD dwFlags = 0, dwMatchedFlags = (MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_DATA);
+
+ std::map<IMFMediaType*, IMFMediaType*>::iterator found = std::find_if(m_TranslatedMediaTypes.begin(), m_TranslatedMediaTypes.end(),
+ [&](std::pair<IMFMediaType*, IMFMediaType*> p)
+ {
+ return (SUCCEEDED(pMediaType->IsEqual(p.first, &dwFlags))
+ && ((dwFlags & dwMatchedFlags) == (dwMatchedFlags)));
+ });
+
+ if (found != m_TranslatedMediaTypes.end())
+ {
+ if (ppIMFMediaTypeFull)
+ {
+ *ppIMFMediaTypeFull = (*found).second;
+ }
+ return true;
+ }
+ else
+ {
+ // Check if we can find it in the Base list.. maybe the mediatype is originally an uncompressed media type
+ return CBasePin::IsMediaTypeSupported(pMediaType,ppIMFMediaTypeFull);
+ }
+}