WMF: fix type negotiation in video probe transform.

- report supported types (same as the video sink)
- handle type changes coming from upstream

Change-Id: I922fc4869ecac3999e055c39adf1b847127a0012
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
This commit is contained in:
Yoann Lopes
2015-11-07 15:53:18 +01:00
parent 43f3d14a99
commit a6164acd2f
3 changed files with 87 additions and 78 deletions

View File

@@ -52,6 +52,7 @@ MFTransform::MFTransform():
m_inputType(0),
m_outputType(0),
m_sample(0),
m_videoSinkTypeHandler(0),
m_bytesPerLine(0)
{
}
@@ -64,8 +65,8 @@ MFTransform::~MFTransform()
if (m_outputType)
m_outputType->Release();
for (int i = 0; i < m_mediaTypes.size(); ++i)
m_mediaTypes[i]->Release();
if (m_videoSinkTypeHandler)
m_videoSinkTypeHandler->Release();
}
void MFTransform::addProbe(MFVideoProbeControl *probe)
@@ -84,12 +85,18 @@ void MFTransform::removeProbe(MFVideoProbeControl *probe)
m_videoProbes.removeOne(probe);
}
void MFTransform::addSupportedMediaType(IMFMediaType *type)
void MFTransform::setVideoSink(IUnknown *videoSink)
{
if (!type)
return;
QMutexLocker locker(&m_mutex);
m_mediaTypes.append(type);
// This transform supports the same input types as the video sink.
// Store its type handler interface in order to report the correct supported types.
if (m_videoSinkTypeHandler) {
m_videoSinkTypeHandler->Release();
m_videoSinkTypeHandler = NULL;
}
if (videoSink)
videoSink->QueryInterface(IID_PPV_ARGS(&m_videoSinkTypeHandler));
}
STDMETHODIMP MFTransform::QueryInterface(REFIID riid, void** ppv)
@@ -228,20 +235,42 @@ STDMETHODIMP MFTransform::AddInputStreams(DWORD cStreams, DWORD *adwStreamIDs)
STDMETHODIMP MFTransform::GetInputAvailableType(DWORD dwInputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
{
// This MFT does not have a list of preferred input types
Q_UNUSED(dwInputStreamID);
Q_UNUSED(dwTypeIndex);
Q_UNUSED(ppType);
return E_NOTIMPL;
// We support the same input types as the video sink
if (!m_videoSinkTypeHandler)
return E_NOTIMPL;
if (dwInputStreamID > 0)
return MF_E_INVALIDSTREAMNUMBER;
if (!ppType)
return E_POINTER;
return m_videoSinkTypeHandler->GetMediaTypeByIndex(dwTypeIndex, ppType);
}
STDMETHODIMP MFTransform::GetOutputAvailableType(DWORD dwOutputStreamID,DWORD dwTypeIndex, IMFMediaType **ppType)
STDMETHODIMP MFTransform::GetOutputAvailableType(DWORD dwOutputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
{
// This MFT does not have a list of preferred output types
Q_UNUSED(dwOutputStreamID);
Q_UNUSED(dwTypeIndex);
Q_UNUSED(ppType);
return E_NOTIMPL;
// Since we don't modify the samples, the output type must be the same as the input type.
// Report our input type as the only available output type.
if (dwOutputStreamID > 0)
return MF_E_INVALIDSTREAMNUMBER;
if (!ppType)
return E_POINTER;
// Input type must be set first
if (!m_inputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (dwTypeIndex > 0)
return MF_E_NO_MORE_TYPES;
// Return a copy to make sure our type is not modified
if (FAILED(MFCreateMediaType(ppType)))
return E_OUTOFMEMORY;
return m_inputType->CopyAllItems(*ppType);
}
STDMETHODIMP MFTransform::SetInputType(DWORD dwInputStreamID, IMFMediaType *pType, DWORD dwFlags)
@@ -257,17 +286,14 @@ STDMETHODIMP MFTransform::SetInputType(DWORD dwInputStreamID, IMFMediaType *pTyp
if (!isMediaTypeSupported(pType))
return MF_E_INVALIDMEDIATYPE;
DWORD flags = 0;
if (pType && !m_inputType && m_outputType && m_outputType->IsEqual(pType, &flags) != S_OK)
return MF_E_INVALIDMEDIATYPE;
if (dwFlags == MFT_SET_TYPE_TEST_ONLY)
return pType ? S_OK : E_POINTER;
if (m_inputType) {
m_inputType->Release();
// Input type has changed, discard output type (if it's set) so it's reset later on
if (m_outputType && m_outputType->IsEqual(pType, &flags) != S_OK) {
DWORD flags = 0;
if (m_outputType && m_outputType->IsEqual(pType, &flags) != S_OK) {
m_outputType->Release();
m_outputType = 0;
}
@@ -286,29 +312,27 @@ STDMETHODIMP MFTransform::SetOutputType(DWORD dwOutputStreamID, IMFMediaType *pT
if (dwOutputStreamID > 0)
return MF_E_INVALIDSTREAMNUMBER;
if (dwFlags == MFT_SET_TYPE_TEST_ONLY && !pType)
return E_POINTER;
QMutexLocker locker(&m_mutex);
// Input type must be set first
if (!m_inputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (m_sample)
return MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
if (!isMediaTypeSupported(pType))
return MF_E_INVALIDMEDIATYPE;
DWORD flags = 0;
if (pType && !m_outputType && m_inputType && m_inputType->IsEqual(pType, &flags) != S_OK)
if (pType && m_inputType->IsEqual(pType, &flags) != S_OK)
return MF_E_INVALIDMEDIATYPE;
if (dwFlags == MFT_SET_TYPE_TEST_ONLY)
return pType ? S_OK : E_POINTER;
if (m_outputType) {
if (m_outputType)
m_outputType->Release();
// Output type has changed, discard input type (if it's set) so it's reset later on
if (m_inputType && m_inputType->IsEqual(pType, &flags) != S_OK) {
m_inputType->Release();
m_inputType = 0;
}
}
m_outputType = pType;
@@ -333,10 +357,11 @@ STDMETHODIMP MFTransform::GetInputCurrentType(DWORD dwInputStreamID, IMFMediaTyp
if (!m_inputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
*ppType = m_inputType;
(*ppType)->AddRef();
// Return a copy to make sure our type is not modified
if (FAILED(MFCreateMediaType(ppType)))
return E_OUTOFMEMORY;
return S_OK;
return m_inputType->CopyAllItems(*ppType);
}
STDMETHODIMP MFTransform::GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaType **ppType)
@@ -349,19 +374,14 @@ STDMETHODIMP MFTransform::GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaT
QMutexLocker locker(&m_mutex);
if (!m_outputType) {
if (m_inputType) {
*ppType = m_inputType;
(*ppType)->AddRef();
return S_OK;
}
if (!m_outputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
}
*ppType = m_outputType;
(*ppType)->AddRef();
// Return a copy to make sure our type is not modified
if (FAILED(MFCreateMediaType(ppType)))
return E_OUTOFMEMORY;
return S_OK;
return m_outputType->CopyAllItems(*ppType);
}
STDMETHODIMP MFTransform::GetInputStatus(DWORD dwInputStreamID, DWORD *pdwFlags)
@@ -374,7 +394,7 @@ STDMETHODIMP MFTransform::GetInputStatus(DWORD dwInputStreamID, DWORD *pdwFlags)
QMutexLocker locker(&m_mutex);
if (!m_inputType)
if (!m_inputType || !m_outputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (m_sample)
@@ -392,7 +412,7 @@ STDMETHODIMP MFTransform::GetOutputStatus(DWORD *pdwFlags)
QMutexLocker locker(&m_mutex);
if (!m_outputType)
if (!m_inputType || !m_outputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (m_sample)
@@ -464,7 +484,7 @@ STDMETHODIMP MFTransform::ProcessInput(DWORD dwInputStreamID, IMFSample *pSample
QMutexLocker locker(&m_mutex);
if (!m_inputType || !m_outputType)
if (!m_inputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (m_sample)
@@ -510,6 +530,14 @@ STDMETHODIMP MFTransform::ProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount,
QMutexLocker locker(&m_mutex);
if (!m_inputType)
return MF_E_TRANSFORM_TYPE_NOT_SET;
if (!m_outputType) {
pOutputSamples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
return MF_E_TRANSFORM_STREAM_CHANGE;
}
if (!m_sample)
return MF_E_TRANSFORM_NEED_MORE_INPUT;
@@ -728,16 +756,10 @@ QByteArray MFTransform::dataFromBuffer(IMFMediaBuffer *buffer, int height, int *
bool MFTransform::isMediaTypeSupported(IMFMediaType *type)
{
// if the list is empty, it supports all formats
if (!type || m_mediaTypes.isEmpty())
// If we don't have the video sink's type handler,
// assume it supports anything...
if (!m_videoSinkTypeHandler || !type)
return true;
for (int i = 0; i < m_mediaTypes.size(); ++i) {
DWORD flags = 0;
m_mediaTypes.at(i)->IsEqual(type, &flags);
if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
return true;
}
return false;
return m_videoSinkTypeHandler->IsMediaTypeSupported(type, NULL) == S_OK;
}

View File

@@ -53,7 +53,7 @@ public:
void addProbe(MFVideoProbeControl* probe);
void removeProbe(MFVideoProbeControl* probe);
void addSupportedMediaType(IMFMediaType *type);
void setVideoSink(IUnknown *videoSink);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
@@ -99,7 +99,7 @@ private:
IMFSample *m_sample;
QMutex m_mutex;
QList<IMFMediaType*> m_mediaTypes;
IMFMediaTypeHandler *m_videoSinkTypeHandler;
QList<MFVideoProbeControl*> m_videoProbes;
QMutex m_videoProbeMutex;

View File

@@ -692,7 +692,6 @@ IMFTopology *MFPlayerSession::insertMFT(IMFTopology *topology, TOPOID outputNode
IUnknown *element = 0;
IMFTopologyNode *node = 0;
IUnknown *outputObject = 0;
IMFMediaTypeHandler *videoSink = 0;
IMFTopologyNode *inputNode = 0;
IMFTopologyNode *mftNode = 0;
bool mftAdded = false;
@@ -711,22 +710,10 @@ IMFTopology *MFPlayerSession::insertMFT(IMFTopology *topology, TOPOID outputNode
if (id != outputNodeId)
break;
// Use output supported media types for the MFT
if (FAILED(node->GetObject(&outputObject)))
break;
if (FAILED(outputObject->QueryInterface(IID_IMFMediaTypeHandler, (void**)&videoSink)))
break;
DWORD mtCount;
if (FAILED(videoSink->GetMediaTypeCount(&mtCount)))
break;
for (DWORD i = 0; i < mtCount; ++i) {
IMFMediaType *type = 0;
if (SUCCEEDED(videoSink->GetMediaTypeByIndex(i, &type)))
m_videoProbeMFT->addSupportedMediaType(type);
}
m_videoProbeMFT->setVideoSink(outputObject);
// Insert MFT between the output node and the node connected to it.
DWORD outputIndex = 0;
@@ -760,13 +747,13 @@ IMFTopology *MFPlayerSession::insertMFT(IMFTopology *topology, TOPOID outputNode
node->Release();
if (element)
element->Release();
if (videoSink)
videoSink->Release();
if (outputObject)
outputObject->Release();
if (mftAdded)
break;
else
m_videoProbeMFT->setVideoSink(NULL);
}
} while (false);