媒体基金会自定义混音器 MFT 出现错误 MF_E_CANNOT_CREATE_SINK [英] Media foundation custom mixer MFT getting error MF_E_CANNOT_CREATE_SINK

查看:33
本文介绍了媒体基金会自定义混音器 MFT 出现错误 MF_E_CANNOT_CREATE_SINK的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Windows Media Foundation 来创建视频播放应用程序.

I am using Windows Media Foundation for creating video playing app.

我使用 IMFTransform 接口和以下链接中提到的少数其他强制性接口创建了自定义 EVR 混音器.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms701624(v=vs.85).aspx

I have created custom EVR mixer using the IMFTransform interface and few of the other mandatory Interfaces as mentioned in the below link.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms701624(v=vs.85).aspx

我已将自定义混音器创建为 DLL 并成功注册了它.

I have created custom mixer as a DLL and also successful registered it.

然后我在 EVR 中使用以下代码添加了这个自定义混音器:

Then I have added this custom mixer using below code in the EVR:

// Create the video renderer.
hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate);

// Add custom mixer
hr = pActivate->SetGUID(MF_ACTIVATE_CUSTOM_VIDEO_MIXER_CLSID, CLSID_CMyCustomMixerMFT);

EVR 在我的自定义混音器中调用所需的方法,但最后我收到错误 MF_E_CANNOT_CREATE_SINK.

EVR is calling required methods in my custom mixer, but at the end I am getting error MF_E_CANNOT_CREATE_SINK.

对于自定义混音器,我指的是我的混音器的 MFT 实现,我指的是来自 Windows 媒体基金会示例的 mft_grayscale 示例应用程序.大多数 IMFTransform 实现是从这个示例中复制的.
https://msdn.microsoft.com/en-us/library/windows/desktop/bb970487%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

For the custom mixer I am referring to MFT implementation of my mixer, I am referring to mft_grayscale sample application from Windows media foundation samples. Most of the IMFTransform implementation is copied from this sample.
https://msdn.microsoft.com/en-us/library/windows/desktop/bb970487%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

我被这个错误困住了很长时间,无法找到解决这个问题的方法.

I am stuck on this error for long and not able to find way out with this issue.

根据方法的文档 STDMETHODIMP GetDeviceID(IID *pDeviceID)

If a mixer or presenter uses Direct3D 9, it must return the value IID_IDirect3DDevice9 in pDeviceID.
The EVR's default mixer and presenter both return this value.
If you write a custom mixer or presenter, it can return some other value.
However, the mixer and presenter must use matching device identifiers.

自定义混音器应返回与演示者匹配的此值.当我在我的代码中实现自定义混合器时,我将 deviceID 作为 IID_IDirect3DDevice9 返回.

Custom mixer should return this value which matches with presenter. As I am implementing custom mixer in my code I am returning deviceID as IID_IDirect3DDevice9.

我只有一个包含音频和视频的视频流.

I have only one video stream with Audio and Video in it.

GetStreamLimits - 输入和输出流限制设置为 1
GetStreamIDs - 输入 ID 0 和输出 ID 0
AddInputStreams - 在我的混音器中,我没有调用这个方法

GetStreamLimits - Input and Output stream limit set to 1
GetStreamIDs - Input ID 0 and Output ID 0
AddInputStreams - In my mixer I don't get call to this method

按照建议,我将使用 MFTrace 进行调试.

As Suggested I will use MFTrace for debugging.

推荐答案

这是一种实现自定义视频混合器的可能方法,该混合器适用于 Windows 7 和 Microsoft MediaSession/Evr.

Here is a possible way to implement a Custom Video Mixer wich works on Windows 7 and Microsoft MediaSession/Evr.

我发现 dxva2 可以用于两种 NV12 流格式.当然,我们不能将流与 alpha 混合,但它有效.我的图形驱动程序告诉我 dxva2 子流只能处理 AYUV/AI44,但 NV12 也可以(奇怪).NV12 没有 alpha,但如果我们不叠加它们,我们可以显示两个视频(也许更多).我还发现 CLSID_CColorConvertDMO 未能为 AYUV 提供 MediaSession/Evr 和自定义视频混合器.颜色转换可以在自定义视频混合器中完成.

I discovered that dxva2 can be use with two NV12 stream format. Of course, we can't mix streams with alpha, but it works. My graphic driver tells me that the dxva2 substream can handle only AYUV/AI44, but NV12 works too (strangely). NV12 has no alpha, but we can show two videos (and perhaps more) if we don't superimposed them. I also discovered that CLSID_CColorConvertDMO failed to provide AYUV with a MediaSession/Evr and a Custom Video Mixer. The color conversion could be done in the Custom Video Mixer.

我会多次发布代码,所以请耐心等待.在这里很难格式化代码.对于代码的某些部分,您将需要来自 MFNode

I will post code in several times, so be patient. It is hard to format code here. For some parts of the code, you will need common files from MFNode

有些接口只是简单地返回E_NOTIMPL,它们只是为了检查Evr需要什么.所以我省略了使用 E_NOTIMPL 的代码.

Some interface simply return E_NOTIMPL, they are just here to check what Evr needs. So i ommited code where E_NOTIMPL is used.

自定义视频混合器类:

//----------------------------------------------------------------------------------------------
// CustomVideoMixer.h
//----------------------------------------------------------------------------------------------
#ifndef MFTCUSTOMVIDEOMIXER_H
#define MFTCUSTOMVIDEOMIXER_H

class CCustomVideoMixer :
    BaseObject,
    public IMFVideoDeviceID,
    public IMFGetService,
    public IMFTopologyServiceLookupClient,
    public IMFTransform,
    public IMFVideoMixerControl,
    public IMFVideoProcessor,
    public IMFAttributes,
    public IMFVideoMixerBitmap,
    public IMFVideoPositionMapper
{

public:

    // CustomVideoMixer.cpp
    static HRESULT CreateInstance(IUnknown*, REFIID, void**);

    // IUnknown - CustomVideoMixer.cpp
    STDMETHODIMP QueryInterface(REFIID, void**);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();

    // IMFVideoDeviceID - CustomVideoMixer.cpp
    STDMETHODIMP GetDeviceID(IID*);

    // IMFGetService - CustomVideoMixer.cpp
    STDMETHODIMP GetService(REFGUID, REFIID, LPVOID*);

    // IMFTopologyServiceLookupClient - CustomVideoMixer.cpp
    STDMETHODIMP InitServicePointers(IMFTopologyServiceLookup*);
    STDMETHODIMP ReleaseServicePointers();

    // IMFTransform - CustomVideoMixer_Transform.cpp
    STDMETHODIMP GetStreamLimits(DWORD*, DWORD*, DWORD*, DWORD*);
    STDMETHODIMP GetStreamCount(DWORD*, DWORD*);
    STDMETHODIMP GetStreamIDs(DWORD, DWORD*, DWORD, DWORD*);
    STDMETHODIMP GetInputStreamInfo(DWORD, MFT_INPUT_STREAM_INFO*);
    STDMETHODIMP GetOutputStreamInfo(DWORD, MFT_OUTPUT_STREAM_INFO*);
    STDMETHODIMP GetAttributes(IMFAttributes**);
    STDMETHODIMP GetInputStreamAttributes(DWORD, IMFAttributes**);
    STDMETHODIMP GetOutputStreamAttributes(DWORD, IMFAttributes**);
    STDMETHODIMP DeleteInputStream(DWORD);
    STDMETHODIMP AddInputStreams(DWORD, DWORD*);
    STDMETHODIMP GetInputAvailableType(DWORD, DWORD, IMFMediaType**);
    STDMETHODIMP GetOutputAvailableType(DWORD, DWORD, IMFMediaType**);
    STDMETHODIMP SetInputType(DWORD, IMFMediaType*, DWORD);
    STDMETHODIMP SetOutputType(DWORD, IMFMediaType*, DWORD);
    STDMETHODIMP GetInputCurrentType(DWORD, IMFMediaType**);
    STDMETHODIMP GetOutputCurrentType(DWORD, IMFMediaType**);
    STDMETHODIMP GetInputStatus(DWORD, DWORD*);
    STDMETHODIMP GetOutputStatus(DWORD*);
    STDMETHODIMP SetOutputBounds(LONGLONG, LONGLONG);
    STDMETHODIMP ProcessEvent(DWORD, IMFMediaEvent*);
    STDMETHODIMP ProcessMessage(MFT_MESSAGE_TYPE, ULONG_PTR);
    STDMETHODIMP ProcessInput(DWORD, IMFSample*, DWORD);
    STDMETHODIMP ProcessOutput(DWORD, DWORD, MFT_OUTPUT_DATA_BUFFER*, DWORD*);

    // IMFVideoMixerControl - CustomVideoMixer_Mixer.cpp
    STDMETHODIMP GetStreamOutputRect(DWORD, MFVideoNormalizedRect*);
    STDMETHODIMP GetStreamZOrder(DWORD, DWORD*);
    STDMETHODIMP SetStreamOutputRect(DWORD, const MFVideoNormalizedRect*);
    STDMETHODIMP SetStreamZOrder(DWORD, DWORD);

    // IMFVideoProcessor - CustomVideoMixer_Mixer.cpp
    STDMETHODIMP GetAvailableVideoProcessorModes(UINT*, GUID**);
    STDMETHODIMP GetBackgroundColor(COLORREF*);
    STDMETHODIMP GetFilteringRange(DWORD, DXVA2_ValueRange*);
    STDMETHODIMP GetFilteringValue(DWORD, DXVA2_Fixed32*);
    STDMETHODIMP GetProcAmpRange(DWORD, DXVA2_ValueRange*);
    STDMETHODIMP GetProcAmpValues(DWORD, DXVA2_ProcAmpValues*);
    STDMETHODIMP GetVideoProcessorCaps(LPGUID, DXVA2_VideoProcessorCaps*);
    STDMETHODIMP GetVideoProcessorMode(LPGUID);
    STDMETHODIMP SetBackgroundColor(COLORREF);
    STDMETHODIMP SetFilteringValue(DWORD, DXVA2_Fixed32*);
    STDMETHODIMP SetProcAmpValues(DWORD, DXVA2_ProcAmpValues*);
    STDMETHODIMP SetVideoProcessorMode(LPGUID);

    // IMFAttributes - CustomVideoMixer_Attributes.cpp
    STDMETHODIMP Compare(IMFAttributes*, MF_ATTRIBUTES_MATCH_TYPE, BOOL*);
    STDMETHODIMP CompareItem(REFGUID, REFPROPVARIANT, BOOL*);
    STDMETHODIMP CopyAllItems(IMFAttributes*);
    STDMETHODIMP DeleteAllItems();
    STDMETHODIMP DeleteItem(REFGUID);
    STDMETHODIMP GetAllocatedBlob(REFGUID, UINT8**, UINT32*);
    STDMETHODIMP GetAllocatedString(REFGUID, LPWSTR*, UINT32*);
    STDMETHODIMP GetBlob(REFGUID, UINT8*, UINT32, UINT32*);
    STDMETHODIMP GetBlobSize(REFGUID, UINT32*);
    STDMETHODIMP GetCount(UINT32*);
    STDMETHODIMP GetDouble(REFGUID, double*);
    STDMETHODIMP GetGUID(REFGUID, GUID*);
    STDMETHODIMP GetItem(REFGUID, PROPVARIANT*);
    STDMETHODIMP GetItemByIndex(UINT32, GUID*, PROPVARIANT*);
    STDMETHODIMP GetItemType(REFGUID, MF_ATTRIBUTE_TYPE*);
    STDMETHODIMP GetString(REFGUID, LPWSTR, UINT32, UINT32*);
    STDMETHODIMP GetStringLength(REFGUID, UINT32*);
    STDMETHODIMP GetUINT32(REFGUID, UINT32*);
    STDMETHODIMP GetUINT64(REFGUID, UINT64*);
    STDMETHODIMP GetUnknown(REFGUID, REFIID, LPVOID*);
    STDMETHODIMP LockStore();
    STDMETHODIMP SetBlob(REFGUID, const UINT8*, UINT32);
    STDMETHODIMP SetDouble(REFGUID, double);
    STDMETHODIMP SetGUID(REFGUID, REFGUID);
    STDMETHODIMP SetItem(REFGUID, REFPROPVARIANT);
    STDMETHODIMP SetString(REFGUID, LPCWSTR);
    STDMETHODIMP SetUINT32(REFGUID, UINT32);
    STDMETHODIMP SetUINT64(REFGUID, UINT64);
    STDMETHODIMP SetUnknown(REFGUID, IUnknown*);
    STDMETHODIMP UnlockStore();

    // IMFVideoMixerBitmap - CustomVideoMixer_Bitmap.cpp
    STDMETHODIMP ClearAlphaBitmap();
    STDMETHODIMP GetAlphaBitmapParameters(MFVideoAlphaBitmapParams*);
    STDMETHODIMP SetAlphaBitmap(const MFVideoAlphaBitmap*);
    STDMETHODIMP UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams*);

    // IMFVideoPositionMapper - CustomVideoMixer_Bitmap.cpp
    STDMETHODIMP MapOutputCoordinateToInputStream(float, float, DWORD, DWORD, float*, float*);


private:

    // CustomVideoMixer.cpp
    CCustomVideoMixer();
    virtual ~CCustomVideoMixer();

    CriticSection m_CriticSection;
    volatile long m_nRefCount;

    CDxva2Manager m_cDxva2Manager;

    IMediaEventSink* m_pMediaEventSink;

    IMFMediaType* m_pRefInputType;
    IMFMediaType* m_pSubInputType;
    IMFMediaType* m_pOutputType;

    BOOL m_bDraining;
    DWORD m_dwInputStreamCount;
    BOOL m_bHaveRefOuput;
    BOOL m_bHaveSubOuput;

    // CustomVideoMixer.cpp
    HRESULT SetD3DManager(IDirect3DDeviceManager9*);
    HRESULT BeginStreaming(ULONG_PTR);
    HRESULT Flush();

    // CustomVideoMixer_Type.cpp
    HRESULT GetOutputType(IMFMediaType**);
};

#endif

CustomVideoMixer.cpp :

CustomVideoMixer.cpp :

//----------------------------------------------------------------------------------------------
// CustomVideoMixer.cpp
//----------------------------------------------------------------------------------------------
#include "StdAfx.h"

CCustomVideoMixer::CCustomVideoMixer()
    : m_nRefCount(1),
    m_pMediaEventSink(NULL),
    m_pRefInputType(NULL),
    m_pSubInputType(NULL),
    m_pOutputType(NULL),
    m_bDraining(FALSE),
    m_dwInputStreamCount(1),
    m_bHaveRefOuput(FALSE),
    m_bHaveSubOuput(FALSE)
{
    TRACE_TRANSFORM((L"CustomVideoMixer::CTOR"));
}

CCustomVideoMixer::~CCustomVideoMixer() {

    TRACE_TRANSFORM((L"CustomVideoMixer::DTOR"));

    AutoLock lock(m_CriticSection);

    Flush();

    m_cDxva2Manager.ReleaseDxva2();
    SAFE_RELEASE(m_pMediaEventSink);
    SAFE_RELEASE(m_pRefInputType);
    SAFE_RELEASE(m_pSubInputType);
    SAFE_RELEASE(m_pOutputType);
}

HRESULT CCustomVideoMixer::CreateInstance(IUnknown* pUnkOuter, REFIID iid, void** ppv) {

    TRACE_TRANSFORM((L"CustomVideoMixer::CreateInstance"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (ppv == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (pUnkOuter != NULL ? CLASS_E_NOAGGREGATION : S_OK));

    CCustomVideoMixer* pMFT = new (std::nothrow)CCustomVideoMixer;

    IF_FAILED_RETURN(pMFT == NULL ? E_OUTOFMEMORY : S_OK);

    LOG_HRESULT(hr = pMFT->QueryInterface(iid, ppv));

    SAFE_RELEASE(pMFT);

    return hr;
}

ULONG CCustomVideoMixer::AddRef() {

    LONG lRef = InterlockedIncrement(&m_nRefCount);

    TRACE_REFCOUNT((L"CustomVideoMixer::AddRef m_nRefCount = %d", lRef));

    return lRef;
}

ULONG CCustomVideoMixer::Release() {

    ULONG uCount = InterlockedDecrement(&m_nRefCount);

    TRACE_REFCOUNT((L"CustomVideoMixer::Release m_nRefCount = %d", uCount));

    if (uCount == 0) {
        delete this;
    }

    return uCount;
}

HRESULT CCustomVideoMixer::QueryInterface(REFIID riid, void** ppv) {

    TRACE_TRANSFORM((L"CustomVideoMixer::QI : riid = %s", GetIIDString(riid)));

    // IMFQualityAdvise
    // IEVRTrustedVideoPlugin

    static const QITAB qit[] = {
        QITABENT(CCustomVideoMixer, IMFVideoDeviceID),
        QITABENT(CCustomVideoMixer, IMFGetService),
        QITABENT(CCustomVideoMixer, IMFTopologyServiceLookupClient),
        QITABENT(CCustomVideoMixer, IMFTransform),
        QITABENT(CCustomVideoMixer, IMFVideoMixerControl),
        QITABENT(CCustomVideoMixer, IMFVideoProcessor),
        QITABENT(CCustomVideoMixer, IMFAttributes),
        QITABENT(CCustomVideoMixer, IMFVideoMixerBitmap),
        QITABENT(CCustomVideoMixer, IMFVideoPositionMapper),
        { 0 }
    };

    return QISearch(this, qit, riid, ppv);
}

HRESULT CCustomVideoMixer::GetDeviceID(IID* pDeviceID) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetDeviceID"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (pDeviceID == NULL ? E_POINTER : S_OK));

    *pDeviceID = IID_IDirect3DDevice9;
    return hr;
}

HRESULT CCustomVideoMixer::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetService : guidService = %s - riid = %s", MFServiceString(guidService), GetIIDString(riid)));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (ppvObject == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (guidService != MR_VIDEO_MIXER_SERVICE ? MF_E_UNSUPPORTED_SERVICE : S_OK));

    if (riid == IID_IMFVideoMixerControl || riid == IID_IMFVideoProcessor || riid == IID_IMFTransform) {

        hr = QueryInterface(riid, ppvObject);
    }
    else {

        LOG_HRESULT(hr = MF_E_UNSUPPORTED_SERVICE);
    }

    return hr;
}

HRESULT CCustomVideoMixer::InitServicePointers(IMFTopologyServiceLookup* pLookup) {

    TRACE_TRANSFORM((L"CustomVideoMixer::InitServicePointers"));

    // https://msdn.microsoft.com/en-us/library/windows/desktop/dd319606(v=vs.85).aspx
    // https://msdn.microsoft.com/en-us/library/windows/desktop/dd406901(v=vs.85).aspx

    HRESULT hr;
    IF_FAILED_RETURN(hr = (pLookup == NULL ? E_POINTER : S_OK));

    AutoLock lock(m_CriticSection);

    //IF_FAILED_RETURN(hr = (IsActive() ? MF_E_INVALIDREQUEST : S_OK));

    SAFE_RELEASE(m_pMediaEventSink);

    DWORD dwObjectCount = 1;

    (void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pMediaEventSink), &dwObjectCount);

    IF_FAILED_RETURN(hr = (m_pMediaEventSink == NULL ? E_POINTER : S_OK));

    // IMFClock* pInterface = NULL;
    // (void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pInterface), &dwObjectCount);
    // SAFE_RELEASE(pInterface);

    // IMFVideoPresenter* pInterface = NULL;
    // (void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pInterface), &dwObjectCount);
    // IF_FAILED_RETURN(hr = (pInterface == NULL ? E_POINTER : S_OK));
    // SAFE_RELEASE(pInterface);

    // IMFVideoRenderer* pInterface2 = NULL;
    // (void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pInterface2), &dwObjectCount);
    // IF_FAILED_RETURN(hr = (pInterface2 == NULL ? E_POINTER : S_OK));
    // SAFE_RELEASE(pInterface2);

    return hr;
}

HRESULT CCustomVideoMixer::ReleaseServicePointers() {

    TRACE_TRANSFORM((L"CustomVideoMixer::ReleaseServicePointers"));

    AutoLock lock(m_CriticSection);

    SAFE_RELEASE(m_pMediaEventSink);

    return S_OK;
}

HRESULT CCustomVideoMixer::SetD3DManager(IDirect3DDeviceManager9* pDeviceManager) {

    TRACE_TRANSFORM((L"CustomVideoMixer::SetD3DManager"));

    HRESULT hr = S_OK;

    m_cDxva2Manager.ReleaseDxva2();

    if (pDeviceManager != NULL) {

        if (m_pRefInputType != NULL && m_pOutputType != NULL)
            IF_FAILED_RETURN(hr = m_cDxva2Manager.InitDxva2(pDeviceManager, m_pOutputType, m_pRefInputType, m_pSubInputType));
    }

    return hr;
}

HRESULT CCustomVideoMixer::BeginStreaming(ULONG_PTR ulParam) {

    TRACE_TRANSFORM((L"CustomVideoMixer::BeginStreaming"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (m_pMediaEventSink == NULL ? E_POINTER : S_OK));

    //IF_FAILED_RETURN(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, ulParam, 0));
    IF_FAILED_RETURN(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 0, 0));
    IF_FAILED_RETURN(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 1, 0));

    // MF_E_INVALIDSTREAMNUMBER
    // MF_E_TRANSFORM_TYPE_NOT_SET

    return hr;
}

HRESULT CCustomVideoMixer::Flush() {

    TRACE_TRANSFORM((L"CustomVideoMixer::Flush"));

    m_bDraining = FALSE;
    m_bHaveRefOuput = FALSE;
    m_bHaveSubOuput = FALSE;
    return S_OK;
}

CustomVideoMixer_Transform.cpp :

CustomVideoMixer_Transform.cpp :

//----------------------------------------------------------------------------------------------
// CustomVideoMixer_Transform.cpp
//----------------------------------------------------------------------------------------------
#include "StdAfx.h"

HRESULT CCustomVideoMixer::GetStreamLimits(DWORD* pdwInputMinimum, DWORD* pdwInputMaximum, DWORD* pdwOutputMinimum, DWORD* pdwOutputMaximum) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetStreamLimits"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = ((pdwInputMinimum == NULL || pdwInputMaximum == NULL || pdwOutputMinimum == NULL || pdwOutputMaximum == NULL) ? E_POINTER : S_OK));

    *pdwInputMinimum = 1;
    *pdwInputMaximum = 16;
    *pdwOutputMinimum = 1;
    *pdwOutputMaximum = 1;

    return hr;
}

HRESULT CCustomVideoMixer::GetStreamCount(DWORD* pcInputStreams, DWORD* pcOutputStreams) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetStreamCount"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = ((pcInputStreams == NULL || pcOutputStreams == NULL) ? E_POINTER : S_OK));

    *pcInputStreams = m_dwInputStreamCount;
    *pcOutputStreams = 1;

    return hr;
}

HRESULT CCustomVideoMixer::GetStreamIDs(DWORD dwInputIDArraySize, DWORD* pdwInputIDs, DWORD dwOutputIDArraySize, DWORD* pdwOutputIDs) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetStreamIDs"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (dwInputIDArraySize == 0 || dwOutputIDArraySize  == 0 ? MF_E_BUFFERTOOSMALL : S_OK));
    IF_FAILED_RETURN(hr = (pdwInputIDs == NULL || pdwOutputIDs == NULL ? E_POINTER : S_OK));

    *pdwOutputIDs = 0;

    if (m_dwInputStreamCount == 1)
        *pdwInputIDs = 0;
    else
        IF_FAILED_RETURN(hr = E_FAIL);

    return hr;
}

HRESULT CCustomVideoMixer::GetInputStreamInfo(DWORD dwInputStreamID, MFT_INPUT_STREAM_INFO* pStreamInfo) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetInputStreamInfo"));

    TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (pStreamInfo == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));

    pStreamInfo->dwFlags =
        MFT_INPUT_STREAM_WHOLE_SAMPLES |
        MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
        MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE |
        MFT_INPUT_STREAM_DOES_NOT_ADDREF;
    pStreamInfo->hnsMaxLatency = 0;
    pStreamInfo->cbSize = 0;
    pStreamInfo->cbMaxLookahead = 0;
    pStreamInfo->cbAlignment = 0;

    return hr;
}

HRESULT CCustomVideoMixer::GetOutputStreamInfo(DWORD dwOutputStreamID, MFT_OUTPUT_STREAM_INFO* pStreamInfo) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputStreamInfo"));

    TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (pStreamInfo == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));

    AutoLock lock(m_CriticSection);

    pStreamInfo->dwFlags =
        MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
        MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
        MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE |
        MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;

    pStreamInfo->cbAlignment = 0;
    pStreamInfo->cbSize = 0;

    return hr;
}

HRESULT CCustomVideoMixer::GetAttributes(IMFAttributes** ppAttributes) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetAttributes"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (ppAttributes == NULL ? E_POINTER : S_OK));

    *ppAttributes = this;
    (*ppAttributes)->AddRef();

    return hr;
}

HRESULT CCustomVideoMixer::GetInputStreamAttributes(DWORD dwInputStreamID, IMFAttributes** ppAttributes) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetInputStreamAttributes"));

    TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
    IF_FAILED_RETURN(hr = (ppAttributes == NULL ? E_POINTER : S_OK));

    *ppAttributes = this;
    (*ppAttributes)->AddRef();

    return hr;
}

HRESULT CCustomVideoMixer::GetOutputStreamAttributes(DWORD dwOutputStreamID, IMFAttributes** ppAttributes) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputStreamAttributes"));

    TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
    IF_FAILED_RETURN(hr = (ppAttributes == NULL ? E_POINTER : S_OK));

    *ppAttributes = this;
    (*ppAttributes)->AddRef();

    return hr;
}

HRESULT CCustomVideoMixer::DeleteInputStream(DWORD dwStreamID) {

    TRACE_TRANSFORM((L"CustomVideoMixer::DeleteInputStream"));

    TRACE_TRANSFORM((L"dwStreamID = %d", dwStreamID));

    if (dwStreamID == 0)
        return MF_E_INVALIDREQUEST;
    else if (dwStreamID != 1)
        return MF_E_INVALIDSTREAMNUMBER;
    else if(m_dwInputStreamCount != 2)
        return MF_E_INVALIDREQUEST;

    //MF_E_TRANSFORM_INPUT_REMAINING

    m_dwInputStreamCount--;

    return S_OK;
}

HRESULT CCustomVideoMixer::AddInputStreams(DWORD cStreams, DWORD* adwStreamIDs) {

    TRACE_TRANSFORM((L"CustomVideoMixer::AddInputStreams"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (cStreams != 1 ? E_INVALIDARG : S_OK));
    IF_FAILED_RETURN(hr = (adwStreamIDs == NULL ? E_INVALIDARG : S_OK));
    IF_FAILED_RETURN(hr = (*adwStreamIDs != 1 ? E_INVALIDARG : S_OK));

    if (m_dwInputStreamCount == 1)
        m_dwInputStreamCount++;
    else
        IF_FAILED_RETURN(hr = E_INVALIDARG);

    return S_OK;
}

HRESULT CCustomVideoMixer::GetInputAvailableType(DWORD dwInputStreamID, DWORD dwTypeIndex, IMFMediaType** ppType) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetInputAvailableType"));

    TRACE_TRANSFORM((L"dwInputStreamID = %d - dwTypeIndex = %d", dwInputStreamID, dwTypeIndex));

    return MF_E_NO_MORE_TYPES;
}

HRESULT CCustomVideoMixer::GetOutputAvailableType(DWORD dwOutputStreamID, DWORD dwTypeIndex, IMFMediaType** ppType) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputAvailableType"));

    TRACE_TRANSFORM((L"dwOutputStreamID = %d - dwTypeIndex = %d", dwOutputStreamID, dwTypeIndex));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (ppType == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
    IF_FAILED_RETURN(hr = (dwTypeIndex != 0 ? MF_E_NO_MORE_TYPES : S_OK));

    AutoLock lock(m_CriticSection);

    if (m_pRefInputType == NULL) {
        hr = MF_E_TRANSFORM_TYPE_NOT_SET;
    }
    else {
        hr = GetOutputType(ppType);
    }

    return hr;
}

HRESULT CCustomVideoMixer::SetInputType(DWORD dwInputStreamID, IMFMediaType* pType, DWORD dwFlags) {

    TRACE_TRANSFORM((L"CustomVideoMixer::SetInputType"));

    TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
    IF_FAILED_RETURN(hr = (dwFlags & ~MFT_SET_TYPE_TEST_ONLY ? E_INVALIDARG : S_OK));

    BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);

    TRACE_TRANSFORM((L"bReallySet = %s", bReallySet ? L"TRUE" : L"FALSE"));

    AutoLock lock(m_CriticSection);

    if (pType) {

        LogMediaType(pType);
    }
    else {

        if (dwInputStreamID == 0)
            SAFE_RELEASE(m_pRefInputType);
        else
            SAFE_RELEASE(m_pSubInputType);

        return hr;
    }

    if (bReallySet) {

        if (dwInputStreamID == 0) {

            SAFE_RELEASE(m_pRefInputType);
            m_pRefInputType = pType;
            m_pRefInputType->AddRef();
        }
        else {

            SAFE_RELEASE(m_pSubInputType);
            m_pSubInputType = pType;
            m_pSubInputType->AddRef();
        }
    }

    return hr;
}

HRESULT CCustomVideoMixer::SetOutputType(DWORD dwOutputStreamID, IMFMediaType* pType, DWORD dwFlags) {

    TRACE_TRANSFORM((L"CustomVideoMixer::SetOutputType"));

    TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
    IF_FAILED_RETURN(hr = (dwFlags & ~MFT_SET_TYPE_TEST_ONLY ? E_INVALIDARG : S_OK));

    BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);

    TRACE_TRANSFORM((L"bReallySet = %s", bReallySet ? L"TRUE" : L"FALSE"));

    AutoLock lock(m_CriticSection);

    if (pType) {

        LogMediaType(pType);
    }
    else {

        SAFE_RELEASE(m_pOutputType);
        return hr;
    }

    if (bReallySet) {

        SAFE_RELEASE(m_pOutputType);
        m_pOutputType = pType;
        m_pOutputType->AddRef();
    }

    return hr;
}

HRESULT CCustomVideoMixer::GetInputCurrentType(DWORD dwInputStreamID, IMFMediaType** ppType) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetInputCurrentType"));

    TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (ppType == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));

    AutoLock lock(m_CriticSection);

    IMFMediaType* m_pInputType = dwInputStreamID == 0 ? m_pRefInputType : m_pSubInputType;

    if (!m_pInputType) {
        hr = MF_E_TRANSFORM_TYPE_NOT_SET;
    }
    else {

        // Todo : clone MediaType
        *ppType = m_pInputType;
        (*ppType)->AddRef();
    }

    return hr;
}

HRESULT CCustomVideoMixer::GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaType** ppType) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputCurrentType"));

    TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (ppType == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));

    AutoLock lock(m_CriticSection);

    if (!m_pOutputType) {
        hr = MF_E_TRANSFORM_TYPE_NOT_SET;
    }
    else {

        // Todo : clone MediaType
        *ppType = m_pOutputType;
        (*ppType)->AddRef();
    }

    return hr;
}

HRESULT CCustomVideoMixer::GetInputStatus(DWORD dwInputStreamID, DWORD* pdwFlags) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetInputStatus"));

    TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (pdwFlags == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));

    AutoLock lock(m_CriticSection);

    // I think we can always process
    *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;

    return hr;
}

HRESULT CCustomVideoMixer::GetOutputStatus(DWORD* pdwFlags) {

    TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputStatus"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (pdwFlags == NULL ? E_POINTER : S_OK));

    AutoLock lock(m_CriticSection);

    /*if (m_bHaveOuput) {
        *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
    }
    else {
        *pdwFlags = 0;
    }*/

    return hr;
}

HRESULT CCustomVideoMixer::SetOutputBounds(LONGLONG /*hnsLowerBound*/, LONGLONG /*hnsUpperBound*/) {

    TRACE_TRANSFORM((L"CustomVideoMixer::SetOutputBounds"));

    return E_NOTIMPL;
}

HRESULT CCustomVideoMixer::ProcessEvent(DWORD /*dwInputStreamID*/, IMFMediaEvent* /*pEvent */) {

    TRACE_TRANSFORM((L"CustomVideoMixer::ProcessEvent"));

    return E_NOTIMPL;
}

HRESULT CCustomVideoMixer::ProcessMessage(MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) {

    TRACE_TRANSFORM((L"CustomVideoMixer::ProcessMessage : %s (Param = %d)", MFTMessageString(eMessage), ulParam));

    HRESULT hr = S_OK;

    AutoLock lock(m_CriticSection);

    switch (eMessage) {

    case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
        //case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
        hr = BeginStreaming(ulParam);
        break;

    case MFT_MESSAGE_COMMAND_FLUSH:
    case MFT_MESSAGE_NOTIFY_END_STREAMING:
    case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
        hr = Flush();
        break;

    case MFT_MESSAGE_COMMAND_DRAIN:
        m_bDraining = TRUE;
        break;

    case MFT_MESSAGE_SET_D3D_MANAGER:
        hr = SetD3DManager(reinterpret_cast<IDirect3DDeviceManager9*>(ulParam));
        // hr = MF_E_UNSUPPORTED_D3D_TYPE...
        break;
    }

    return hr;
}

HRESULT CCustomVideoMixer::ProcessInput(DWORD dwInputStreamID, IMFSample* pSample, DWORD dwFlags) {

    TRACE_TRANSFORM((L"CustomVideoMixer::ProcessInput"));

    TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (pSample == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
    IF_FAILED_RETURN(hr = (dwFlags != 0 ? E_INVALIDARG : S_OK));

    AutoLock lock(m_CriticSection);

    if (m_bHaveRefOuput || m_bHaveSubOuput) {
        return MF_E_NOTACCEPTING;
    }

    if (SUCCEEDED(hr = m_cDxva2Manager.ProcessInput(pSample, dwInputStreamID))) {

        if (dwInputStreamID == 0) {

            m_bHaveRefOuput = TRUE;

            LOG_HRESULT(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 0, 0));
        }
        else {

            m_bHaveSubOuput = TRUE;

            LOG_HRESULT(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 1, 0));
        }
    }

    return hr;
}

HRESULT CCustomVideoMixer::ProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER* pOutputSamples, DWORD* pdwStatus) {

    TRACE_TRANSFORM((L"CustomVideoMixer::ProcessOutput"));

    HRESULT hr;
    IF_FAILED_RETURN(hr = (dwFlags != 0 ? E_INVALIDARG : S_OK));
    IF_FAILED_RETURN(hr = (cOutputBufferCount != 1 ? E_INVALIDARG : S_OK));
    IF_FAILED_RETURN(hr = ((pOutputSamples == NULL || pdwStatus == NULL) ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (pOutputSamples[0].dwStreamID != 0 ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (pOutputSamples[0].pSample == NULL ? E_INVALIDARG : S_OK));

    AutoLock lock(m_CriticSection);

    if (m_bHaveRefOuput || m_bHaveSubOuput) {

        IF_FAILED_RETURN(hr = m_cDxva2Manager.ProcessOutput(pOutputSamples[0].pSample));

        if(m_bHaveRefOuput)
            m_bHaveRefOuput = FALSE;

        if (m_bHaveSubOuput)
            m_bHaveSubOuput = FALSE;
    }
    else {

        return MF_E_TRANSFORM_NEED_MORE_INPUT;
    }

    return hr;
}

这篇关于媒体基金会自定义混音器 MFT 出现错误 MF_E_CANNOT_CREATE_SINK的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆