Media foundation custom mixer MFT getting error MF

2019-07-24 19:27发布

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

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

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

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 is calling required methods in my custom mixer, but at the end I am getting error MF_E_CANNOT_CREATE_SINK.

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.

** EDIT **

As per the documentation for the method 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.

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.

Update

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

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

As Suggested I will use MFTrace for debugging.

4条回答
狗以群分
2楼-- · 2019-07-24 19:42

Here is a possible way to implement a Custom Video Mixer wich works on Windows 7 and Microsoft 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.

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

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

The Custom Video Mixer class :

//----------------------------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------------------------
#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
//----------------------------------------------------------------------------------------------
#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;
}
查看更多
迷人小祖宗
3楼-- · 2019-07-24 19:42

Finally, the EvrMediaSession code :

//----------------------------------------------------------------------------------------------
// Main.cpp
//----------------------------------------------------------------------------------------------
#pragma once
#define WIN32_LEAN_AND_MEAN
#define STRICT

#include <WinSDKVer.h>
#include <new>
#include <windows.h>

//----------------------------------------------------------------------------------------------
// Common MFNode Files
#ifdef _DEBUG
#define MF_USE_LOGGING 1
#else
#define MF_USE_LOGGING 0
#endif

#include "C:\Project\MFNode\Common\MFInclude.h"

// {B2F74C92-79DF-45DE-9C55-A99DE8276679}
DEFINE_GUID(CLSID_CustomVideoMixer, 0xb2f74c92, 0x79df, 0x45de, 0x9c, 0x55, 0xa9, 0x9d, 0xe8, 0x27, 0x66, 0x79);

#define WINDOWAPPLICATION_CLASS L"WindowApplication"

// Hardcoded : change if needed
#define VIDEO_WIDTH_1 320
#define VIDEO_HEIGHT_1 240
#define VIDEO_FILE_1 L"C:\\Project\\h264\\big_buck_bunny_240p_5mb.mp4"
#define VIDEO_FILE_2 L"C:\\Project\\h264\\big_buck_bunny_240p_5mb - Copie.mp4"

HWND g_hWnd = NULL;
HANDLE g_hSessionEvent = NULL;
IMFMediaSession* g_pSession = NULL;
IMFMediaSource* g_pVideoSource1 = NULL;
IMFMediaSource* g_pVideoSource2 = NULL;
IMFMediaSource* g_pAggregatedSource = NULL;

class CCustomAsyncCallback : public IMFAsyncCallback {

public:

    CCustomAsyncCallback() : m_nRefCount(1) {}
    virtual ~CCustomAsyncCallback() {}

    // IUnknown
    STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {

        static const QITAB qit[] = {
            QITABENT(CCustomAsyncCallback, IMFAsyncCallback),
            { 0 }
        };

        return QISearch(this, qit, riid, ppv);
    }
    STDMETHODIMP_(ULONG) AddRef() {

        LONG lRef = InterlockedIncrement(&m_nRefCount);
        return lRef;
    }
    STDMETHODIMP_(ULONG) Release() {

        ULONG uCount = InterlockedDecrement(&m_nRefCount);

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

        return uCount;
    }

    // IMFAsyncCallback
    STDMETHODIMP GetParameters(DWORD*, DWORD*) { return E_NOTIMPL; }
    STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult) {

        IMFMediaEvent* pEvent = NULL;
        HRESULT hr = S_OK;
        HRESULT hrStatus;
        MediaEventType EventType;

        AutoLock lock(m_CriticSection);

        try {

            IF_FAILED_THROW(hr = g_pSession->EndGetEvent(pAsyncResult, &pEvent));

            IF_FAILED_THROW(hr = pEvent->GetType(&EventType));

            TRACE((L"Invoke %s", MFEventString(EventType)));

            IF_FAILED_THROW(hr = pEvent->GetStatus(&hrStatus));

            if (FAILED(hrStatus)) {

                LOG_HRESULT(hr = hrStatus);

                LOG_HRESULT(hr = g_pSession->BeginGetEvent(this, NULL));
                SAFE_RELEASE(pEvent);

                //SetEvent(g_hSessionEvent);

                return S_OK;
            }

            if (EventType == MESessionTopologyStatus) {

                MF_TOPOSTATUS TopoStatus = MF_TOPOSTATUS_INVALID;
                LOG_HRESULT(hr = pEvent->GetUINT32(MF_EVENT_TOPOLOGY_STATUS, (UINT32*)&TopoStatus));
                TRACE((L"TopoStatus %s", MFTopologyStatusString(TopoStatus)));

                if(TopoStatus == MF_TOPOSTATUS_READY)
                    SetEvent(g_hSessionEvent);
            }

            if (EventType != MESessionClosed) {

                LOG_HRESULT(hr = g_pSession->BeginGetEvent(this, NULL));
            }
            else {
                SetEvent(g_hSessionEvent);
            }
        }
        catch (HRESULT) {}

        SAFE_RELEASE(pEvent);

        return S_OK;
    }

private:

    CriticSection m_CriticSection;
    volatile long m_nRefCount;
};

CCustomAsyncCallback* g_pCustomAsyncCallback = NULL;

void FreeMediaObject();
HRESULT ProcessVideo();
HRESULT CreateMediaSource(IMFMediaSource**, LPCWSTR);
HRESULT CreateAggregatedSource(IMFMediaSource*, IMFMediaSource*, IMFMediaSource**);
HRESULT CreateTopologyAggregated(IMFTopology**, IMFMediaSource*);
HRESULT BuildTopology(IMFTopology*, IMFPresentationDescriptor*, IMFMediaSource*, IMFStreamSink*, IMFStreamSink*);
HRESULT CreateSourceStreamNode(IMFMediaSource*, IMFPresentationDescriptor*, IMFStreamDescriptor*, IMFTopologyNode**);
HRESULT CreateOutputNode(IMFStreamDescriptor*, IMFTopologyNode**, IMFStreamSink*);
HRESULT InitWindow(const UINT, const UINT);
LRESULT CALLBACK WindowApplicationMsgProc(HWND, UINT, WPARAM, LPARAM);

void main() {

    HRESULT hr;

    LOG_HRESULT(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));

    if (SUCCEEDED(hr)) {

        LOG_HRESULT(hr = MFStartup(MF_VERSION, MFSTARTUP_LITE));

        if (SUCCEEDED(hr)) {

            LOG_HRESULT(hr = ProcessVideo());

            if (SUCCEEDED(hr)) {

                MSG msg;
                ZeroMemory(&msg, sizeof(MSG));

                while (GetMessage(&msg, NULL, 0, 0) > 0) {

                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }

            FreeMediaObject();

            LOG_HRESULT(hr = MFShutdown());
        }

        CoUninitialize();
    }
}

void FreeMediaObject() {

    HRESULT hr = S_OK;

    if (g_pSession != NULL) {

        LOG_HRESULT(hr = g_pSession->Close());

        DWORD dwWaitResult = WaitForSingleObject(g_hSessionEvent, 10000);

        if (dwWaitResult == WAIT_TIMEOUT)
        {
            assert(FALSE);
        }
    }

    if (g_pAggregatedSource) {

        g_pAggregatedSource->Shutdown();
        SAFE_RELEASE(g_pAggregatedSource);
    }

    SAFE_RELEASE(g_pVideoSource1);
    SAFE_RELEASE(g_pVideoSource2);
    SAFE_RELEASE(g_pCustomAsyncCallback);

    if (g_pSession) {

        LOG_HRESULT(hr = g_pSession->Shutdown());

        ULONG ulTest = g_pSession->Release();
        g_pSession = NULL;

        assert(ulTest == 0);
    }

    if (g_hSessionEvent)
    {
        CloseHandle(g_hSessionEvent);
        g_hSessionEvent = NULL;
    }

    if (IsWindow(g_hWnd)) {

        DestroyWindow(g_hWnd);
        UnregisterClass(WINDOWAPPLICATION_CLASS, GetModuleHandle(NULL));
        g_hWnd = NULL;
    }
}

HRESULT ProcessVideo() {

    HRESULT hr = S_OK;
    IMFTopology* pTopology = NULL;

    PROPVARIANT varStart;
    PropVariantInit(&varStart);
    varStart.vt = VT_EMPTY;

    try {

        g_pCustomAsyncCallback = new (std::nothrow)CCustomAsyncCallback();
        IF_FAILED_THROW(hr = (g_pCustomAsyncCallback == NULL ? E_OUTOFMEMORY : S_OK));

        g_hSessionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
        IF_FAILED_THROW(hr = (g_hSessionEvent == NULL ? E_OUTOFMEMORY : S_OK));

        IF_FAILED_THROW(hr = CreateMediaSource(&g_pVideoSource1, VIDEO_FILE_1));
        IF_FAILED_THROW(hr = CreateMediaSource(&g_pVideoSource2, VIDEO_FILE_2));
        IF_FAILED_THROW(hr = CreateAggregatedSource(g_pVideoSource1, g_pVideoSource2, &g_pAggregatedSource));

        IF_FAILED_THROW(hr = CreateTopologyAggregated(&pTopology, g_pAggregatedSource));
        IF_FAILED_THROW(hr = MFCreateMediaSession(NULL, &g_pSession));
        IF_FAILED_THROW(hr = g_pSession->BeginGetEvent((IMFAsyncCallback*)g_pCustomAsyncCallback, NULL));
        IF_FAILED_THROW(hr = g_pSession->SetTopology(0, pTopology));

        DWORD dwWaitResult = WaitForSingleObject(g_hSessionEvent, 10000);

        if (dwWaitResult == WAIT_TIMEOUT)
        {
            IF_FAILED_THROW(hr = E_FAIL);
        }

        LOG_HRESULT(hr = g_pSession->Start(&GUID_NULL, &varStart));
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pTopology);

    PropVariantClear(&varStart);

    return hr;
}

HRESULT CreateMediaSource(IMFMediaSource** ppSource, LPCWSTR szURL) {

    HRESULT hr = S_OK;
    MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;

    IMFSourceResolver* pSourceResolver = NULL;
    IUnknown* pSource = NULL;

    try {

        IF_FAILED_THROW(hr = MFCreateSourceResolver(&pSourceResolver));
        IF_FAILED_THROW(hr = pSourceResolver->CreateObjectFromURL(szURL, MF_RESOLUTION_MEDIASOURCE, NULL, &ObjectType, &pSource));
        IF_FAILED_THROW(hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource)));
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pSource);
    SAFE_RELEASE(pSourceResolver);

    return hr;
}

HRESULT CreateAggregatedSource(IMFMediaSource* pSource1, IMFMediaSource* pSource2, IMFMediaSource** ppAggregatedSource) {

    IMFCollection* pCollection = NULL;

    HRESULT hr = MFCreateCollection(&pCollection);

    if (SUCCEEDED(hr)) {

        hr = pCollection->AddElement(pSource1);
    }

    if (SUCCEEDED(hr)) {

        hr = pCollection->AddElement(pSource2);
    }

    if (SUCCEEDED(hr)) {

        hr = MFCreateAggregateSource(pCollection, ppAggregatedSource);
    }

    SAFE_RELEASE(pCollection);

    return hr;
}

HRESULT CreateTopologyAggregated(IMFTopology** ppTopology, IMFMediaSource* pSource) {

    assert(ppTopology != NULL);
    assert(pSource != NULL);

    HRESULT hr = S_OK;

    IMFTopology* pTopology = NULL;
    IMFPresentationDescriptor* pSourcePD = NULL;
    IMFActivate* pEvrActivate = NULL;
    //IMFVideoRenderer* pVideoRenderer = NULL;
    IMFMediaSink* pEvrSink = NULL;
    IMFStreamSink* pStreamSink1 = NULL;
    IMFStreamSink* pStreamSink2 = NULL;

    try {

        IF_FAILED_THROW(hr = MFCreateTopology(&pTopology));

        IF_FAILED_THROW(hr = pSource->CreatePresentationDescriptor(&pSourcePD));

        IF_FAILED_THROW(hr = InitWindow(VIDEO_WIDTH_1, VIDEO_HEIGHT_1));
        IF_FAILED_THROW(hr = MFCreateVideoRendererActivate(g_hWnd, &pEvrActivate));
        IF_FAILED_THROW(hr = pEvrActivate->SetGUID(MF_ACTIVATE_CUSTOM_VIDEO_MIXER_CLSID, CLSID_CustomVideoMixer));
        //IF_FAILED_THROW(hr = pEvrActivate->ActivateObject(__uuidof(IMFVideoRenderer), reinterpret_cast<void**>(&pVideoRenderer)));
        //IF_FAILED_THROW(hr = pVideoRenderer->InitializeRenderer(NULL, NULL));

        IF_FAILED_THROW(hr = pEvrActivate->ActivateObject(__uuidof(IMFMediaSink), reinterpret_cast<void**>(&pEvrSink)));
        IF_FAILED_THROW(hr = pEvrSink->GetStreamSinkByIndex(0, &pStreamSink1));
        IF_FAILED_THROW(hr = pEvrSink->AddStreamSink(1, NULL, &pStreamSink2));

        IF_FAILED_THROW(hr = BuildTopology(pTopology, pSourcePD, pSource, pStreamSink1, pStreamSink2));

        *ppTopology = pTopology;
        (*ppTopology)->AddRef();
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pStreamSink2);
    SAFE_RELEASE(pStreamSink1);
    SAFE_RELEASE(pEvrSink);
    //SAFE_RELEASE(pVideoRenderer);
    SAFE_RELEASE(pEvrActivate);
    SAFE_RELEASE(pTopology);
    SAFE_RELEASE(pSourcePD);

    return hr;
}

HRESULT BuildTopology(IMFTopology* pTopology, IMFPresentationDescriptor* pSourcePD, IMFMediaSource* pSource, IMFStreamSink* pStreamSink1, IMFStreamSink* pStreamSink2) {

    assert(pTopology != NULL);

    HRESULT hr = S_OK;

    IMFStreamDescriptor* pSourceSD = NULL;
    IMFTopologyNode* pSourceNode = NULL;
    IMFTopologyNode* pOutputNode = NULL;
    IMFMediaTypeHandler* pHandler = NULL;
    BOOL bSelected = FALSE;
    DWORD dwStreamCount;
    GUID guidMajorType = GUID_NULL;
    BOOL bRef = TRUE;

    try {

        IF_FAILED_THROW(hr = pSourcePD->GetStreamDescriptorCount(&dwStreamCount));

        for (DWORD i = 0; i < dwStreamCount; i++) {

            IF_FAILED_THROW(hr = pSourcePD->GetStreamDescriptorByIndex(i, &bSelected, &pSourceSD));

            if (bSelected) {

                IF_FAILED_THROW(hr = pSourceSD->GetMediaTypeHandler(&pHandler));
                IF_FAILED_THROW(hr = pHandler->GetMajorType(&guidMajorType));

                if (guidMajorType == MFMediaType_Video) {

                    IF_FAILED_THROW(hr = CreateSourceStreamNode(pSource, pSourcePD, pSourceSD, &pSourceNode));

                    if (bRef) {

                        bRef = FALSE;
                        IF_FAILED_THROW(hr = CreateOutputNode(pSourceSD, &pOutputNode, pStreamSink1));

                        IF_FAILED_THROW(hr = pTopology->AddNode(pSourceNode));
                        IF_FAILED_THROW(hr = pTopology->AddNode(pOutputNode));

                        IF_FAILED_THROW(hr = pSourceNode->ConnectOutput(0, pOutputNode, 0));
                    }
                    else {

                        IF_FAILED_THROW(hr = CreateOutputNode(pSourceSD, &pOutputNode, pStreamSink2));

                        IF_FAILED_THROW(hr = pTopology->AddNode(pSourceNode));
                        IF_FAILED_THROW(hr = pTopology->AddNode(pOutputNode));

                        IF_FAILED_THROW(hr = pSourceNode->ConnectOutput(0, pOutputNode, 0));
                    }
                }
                /*else if (guidMajorType == MFMediaType_Audio) {

                    IF_FAILED_THROW(hr = CreateSourceStreamNode(pSource, pSourcePD, pSourceSD, &pSourceNode));
                    IF_FAILED_THROW(hr = CreateOutputNode(pSourceSD, &pOutputNode, NULL));

                    IF_FAILED_THROW(hr = pTopology->AddNode(pSourceNode));
                    IF_FAILED_THROW(hr = pTopology->AddNode(pOutputNode));

                    IF_FAILED_THROW(hr = pSourceNode->ConnectOutput(0, pOutputNode, 0));
                }*/
                else {

                    IF_FAILED_THROW(hr = pSourcePD->DeselectStream(i));
                }

                SAFE_RELEASE(pHandler);
                SAFE_RELEASE(pOutputNode);
                SAFE_RELEASE(pSourceNode);
            }

            SAFE_RELEASE(pSourceSD);
        }
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pHandler);
    SAFE_RELEASE(pOutputNode);
    SAFE_RELEASE(pSourceNode);
    SAFE_RELEASE(pSourceSD);

    return hr;
}

HRESULT CreateSourceStreamNode(IMFMediaSource* pSource, IMFPresentationDescriptor* pSourcePD, IMFStreamDescriptor* pSourceSD, IMFTopologyNode** ppNode) {

    if (!pSource || !pSourcePD || !pSourceSD || !ppNode) {
        return E_POINTER;
    }

    IMFTopologyNode* pNode = NULL;
    HRESULT hr = S_OK;

    try {

        IF_FAILED_THROW(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode));

        IF_FAILED_THROW(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource));

        IF_FAILED_THROW(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pSourcePD));

        IF_FAILED_THROW(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSourceSD));

        *ppNode = pNode;
        (*ppNode)->AddRef();
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pNode);

    return hr;
}

HRESULT CreateOutputNode(IMFStreamDescriptor* pSourceSD, IMFTopologyNode** ppNode, IMFStreamSink* pStreamSink) {

    IMFTopologyNode* pNode = NULL;
    IMFMediaTypeHandler* pHandler = NULL;
    IMFMediaType* pMediaType = NULL;
    IMFActivate* pActivate = NULL;

    GUID guidMajorType = GUID_NULL;
    HRESULT hr = S_OK;

    try {

        IF_FAILED_THROW(hr = pSourceSD->GetMediaTypeHandler(&pHandler));

        IF_FAILED_THROW(hr = pHandler->GetMajorType(&guidMajorType));

        IF_FAILED_THROW(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode));

        if (MFMediaType_Video == guidMajorType) {

            IF_FAILED_THROW(hr = pHandler->GetCurrentMediaType(&pMediaType));
            IF_FAILED_THROW(hr = pMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
            IF_FAILED_THROW(hr = pHandler->SetCurrentMediaType(pMediaType));

            IF_FAILED_THROW(hr = pNode->SetObject(pStreamSink));
        }
        else if (MFMediaType_Audio == guidMajorType) {

            IF_FAILED_THROW(hr = MFCreateAudioRendererActivate(&pActivate));
            IF_FAILED_THROW(hr = pNode->SetObject(pActivate));
        }
        else {

            IF_FAILED_THROW(hr = E_FAIL);
        }

        *ppNode = pNode;
        (*ppNode)->AddRef();
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pNode);
    SAFE_RELEASE(pHandler);
    SAFE_RELEASE(pMediaType);
    SAFE_RELEASE(pActivate);

    return hr;
}

HRESULT InitWindow(const UINT uiWidth, const UINT uiHeight) {

    WNDCLASSEX WndClassEx;

    WndClassEx.cbSize = sizeof(WNDCLASSEX);
    WndClassEx.style = CS_HREDRAW | CS_VREDRAW;
    WndClassEx.lpfnWndProc = WindowApplicationMsgProc;
    WndClassEx.cbClsExtra = 0L;
    WndClassEx.cbWndExtra = 0L;
    WndClassEx.hInstance = GetModuleHandle(NULL);
    WndClassEx.hIcon = NULL;
    WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClassEx.hbrBackground = NULL;
    WndClassEx.lpszMenuName = NULL;
    WndClassEx.lpszClassName = WINDOWAPPLICATION_CLASS;
    WndClassEx.hIconSm = NULL;

    if (!RegisterClassEx(&WndClassEx)) {
        return E_FAIL;
    }

    int iWndL = uiWidth + 8 + GetSystemMetrics(SM_CXSIZEFRAME) * 2;
    int iWndH = uiHeight + 8 + GetSystemMetrics(SM_CYSIZEFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);

    int iXWnd = (GetSystemMetrics(SM_CXSCREEN) - iWndL) / 2;
    int iYWnd = (GetSystemMetrics(SM_CYSCREEN) - iWndH) / 2;

    if ((g_hWnd = CreateWindowEx(WS_EX_ACCEPTFILES, WINDOWAPPLICATION_CLASS, WINDOWAPPLICATION_CLASS, WS_OVERLAPPEDWINDOW, iXWnd, iYWnd,
    iWndL, iWndH, GetDesktopWindow(), NULL, GetModuleHandle(NULL), NULL)) == NULL) {
        return E_FAIL;
    }

    RECT rc;
    GetClientRect(g_hWnd, &rc);

    // If failed change iWndL or/and iWndH to be TRUE
    assert(rc.right == VIDEO_WIDTH_1 && rc.bottom == VIDEO_HEIGHT_1);

    ShowWindow(g_hWnd, SW_SHOW);

    return S_OK;
}

LRESULT CALLBACK WindowApplicationMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {

    if (msg == WM_PAINT) {

        ValidateRect(hWnd, NULL);
        return 0L;
    }
    else if (msg == WM_ERASEBKGND) {

        return 1L;
    }
    else if (msg == WM_CLOSE) {

        PostQuitMessage(0);
        return 0L;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}
查看更多
▲ chillily
4楼-- · 2019-07-24 19:52

The rest of the code.

CustomVideoMixer_Attributes.cpp :

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

HRESULT CCustomVideoMixer::GetUINT32(REFGUID guidKey, UINT32* punValue) {

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

    if (punValue == NULL)
        return E_POINTER;

    if (guidKey == MF_SA_D3D_AWARE) {

        TRACE_TRANSFORM((L"MF_SA_D3D_AWARE"));

        *punValue = TRUE;
        return S_OK;
    }
    else if(guidKey == MF_SA_REQUIRED_SAMPLE_COUNT) {

        TRACE_TRANSFORM((L"MF_SA_REQUIRED_SAMPLE_COUNT"));

        *punValue = 1;
        return S_OK;
    }
    else {

        TRACE_TRANSFORM((L"ERROR : MF_E_ATTRIBUTENOTFOUND"));
    }

    return MF_E_ATTRIBUTENOTFOUND;
}

HRESULT CCustomVideoMixer::SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize) {

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

    if (guidKey == VIDEO_ZOOM_RECT) {

        TRACE_TRANSFORM((L"VIDEO_ZOOM_RECT"));
        return S_OK;
    }
    else {

        TRACE_TRANSFORM((L"ERROR : MF_E_ATTRIBUTENOTFOUND"));
    }

    return MF_E_ATTRIBUTENOTFOUND;
}

CustomVideoMixer_Type.cpp :

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

HRESULT CCustomVideoMixer::GetOutputType(IMFMediaType** ppType) {

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

    HRESULT hr = S_OK;
    IMFMediaType* pOutputType = NULL;

    try {

        IF_FAILED_THROW(hr = MFCreateMediaType(&pOutputType));

        IF_FAILED_THROW(hr = pOutputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
        // MFVideoFormat_ARGB32 MFVideoFormat_RGB32
        IF_FAILED_THROW(hr = pOutputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32));
        IF_FAILED_THROW(hr = pOutputType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE));
        IF_FAILED_THROW(hr = pOutputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE));
        IF_FAILED_THROW(hr = pOutputType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
        IF_FAILED_THROW(hr = MFSetAttributeRatio(pOutputType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1));

        *ppType = pOutputType;
        (*ppType)->AddRef();
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pOutputType);
    return hr;
}

Dxva2 part :

//----------------------------------------------------------------------------------------------
// Dxva2Manager.h
//----------------------------------------------------------------------------------------------
#ifndef DXVA2MANAGER_H
#define DXVA2MANAGER_H

class CDxva2Manager {

    public:

        CDxva2Manager();
        ~CDxva2Manager() { ReleaseDxva2(); }

        HRESULT InitDxva2(IDirect3DDeviceManager9*, IMFMediaType*, IMFMediaType*, IMFMediaType*);
        void ReleaseDxva2();
        HRESULT ProcessInput(IMFSample*, const DWORD);
        HRESULT ProcessOutput(IMFSample*);

    private:

        IDirectXVideoProcessor* m_pVideoProcessor;
        IDirect3DSurface9* m_pRefSurface9;
        IDirect3DSurface9* m_pSubSurface9;

        LONGLONG m_llDuration;
        LONGLONG m_llTime;

        UINT32 m_uiRefWidth;
        UINT32 m_uiRefHeight;
        UINT32 m_uiRefLine;
        UINT32 m_uiSubWidth;
        UINT32 m_uiSubHeight;
        UINT32 m_uiSubLine;

        HRESULT GetDxva2VideoDesc(DXVA2_VideoDesc*, IMFMediaType*);
};

#endif

Dxva2Manager.cpp :

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

CDxva2Manager::CDxva2Manager() :
    m_pVideoProcessor(NULL),
    m_pRefSurface9(NULL),
    m_pSubSurface9(NULL),
    m_llDuration(0LL),
    m_llTime(0LL),
    m_uiRefWidth(0),
    m_uiRefHeight(0),
    m_uiRefLine(0),
    m_uiSubWidth(0),
    m_uiSubHeight(0),
    m_uiSubLine(0)
{
}

HRESULT CDxva2Manager::InitDxva2(IDirect3DDeviceManager9* pDeviceManager, IMFMediaType* pOutputType, IMFMediaType* pRefInputType, IMFMediaType* pSubInputType) {

    assert(m_pVideoProcessor == NULL);
    assert(m_pRefSurface9 == NULL);
    assert(m_pSubSurface9 == NULL);

    HRESULT hr;

    IF_FAILED_RETURN(hr = (pDeviceManager == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (pOutputType == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (pRefInputType == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (pSubInputType == NULL ? E_POINTER : S_OK));

    IDirectXVideoProcessorService* pVideoProcessorService = NULL;
    HANDLE hD3d9Device = INVALID_HANDLE_VALUE;

    GUID subtype = GUID_NULL;
    UINT32 uiWidth = 0;
    UINT32 uiHeight = 0;
    D3DFORMAT D3DFormat = D3DFMT_UNKNOWN;

    DXVA2_VideoDesc dxva2VideoDesc = { 0 };
    UINT uiCount = 0;
    UINT uiStreamCount = 1;
    GUID* guids = NULL;

    try {

        IF_FAILED_THROW(hr = pDeviceManager->OpenDeviceHandle(&hD3d9Device));
        IF_FAILED_THROW(hr = pDeviceManager->GetVideoService(hD3d9Device, IID_PPV_ARGS(&pVideoProcessorService)));

        IF_FAILED_THROW(hr = GetDxva2VideoDesc(&dxva2VideoDesc, pRefInputType));
        IF_FAILED_THROW(hr = pVideoProcessorService->GetVideoProcessorDeviceGuids(&dxva2VideoDesc, &uiCount, &guids));
        IF_FAILED_THROW(hr = pVideoProcessorService->CreateVideoProcessor(guids[0], &dxva2VideoDesc, D3DFMT_X8R8G8B8, uiStreamCount, &m_pVideoProcessor));

        IF_FAILED_THROW(hr = pRefInputType->GetGUID(MF_MT_SUBTYPE, &subtype));
        IF_FAILED_THROW(hr = MFGetAttributeSize(pRefInputType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight));

        if (subtype == MFVideoFormat_NV12)
            D3DFormat = (D3DFORMAT)D3DFMT_NV12;
        else
            IF_FAILED_THROW(hr = E_FAIL);

        IF_FAILED_THROW(hr = pVideoProcessorService->CreateSurface(uiWidth, uiHeight, 0, D3DFormat, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &m_pRefSurface9, NULL));

        m_uiRefWidth = uiWidth;
        m_uiRefHeight = uiHeight;
        m_uiRefLine = m_uiRefHeight + (m_uiRefHeight / 2);

        IF_FAILED_THROW(hr = pSubInputType->GetGUID(MF_MT_SUBTYPE, &subtype));
        IF_FAILED_THROW(hr = MFGetAttributeSize(pSubInputType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight));

        /*if (subtype == MFVideoFormat_AYUV)
            D3DFormat = (D3DFORMAT)D3DFMT_AYUV;
        else
            IF_FAILED_THROW(hr = E_FAIL);*/

        m_uiSubWidth = uiWidth;
        m_uiSubHeight = uiHeight;
        m_uiSubLine = m_uiSubHeight + (m_uiSubHeight / 2);

        IF_FAILED_THROW(hr = pVideoProcessorService->CreateSurface(uiWidth, uiHeight, 0, D3DFormat, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &m_pSubSurface9, NULL));
    }
    catch (HRESULT) {}

    CoTaskMemFree(guids);

    if (hD3d9Device != INVALID_HANDLE_VALUE) {

        LOG_HRESULT(pDeviceManager->CloseDeviceHandle(hD3d9Device));
    }

    SAFE_RELEASE(pVideoProcessorService);

    return hr;
}

void CDxva2Manager::ReleaseDxva2() {

    SAFE_RELEASE(m_pVideoProcessor);
    SAFE_RELEASE(m_pRefSurface9);
    SAFE_RELEASE(m_pSubSurface9);

    m_llDuration = 0LL;
    m_llTime = 0LL;
    m_uiRefWidth = 0;
    m_uiRefHeight = 0;
    m_uiRefLine = 0;
    m_uiSubWidth = 0;
    m_uiSubHeight = 0;
    m_uiSubLine = 0;
}

HRESULT CDxva2Manager::ProcessInput(IMFSample* pSample, const DWORD dwStreamId) {

    HRESULT hr = S_OK;

    IMFMediaBuffer* pBuffer = NULL;
    BYTE* pData = NULL;
    DWORD dwLength = 0;

    IDirect3DSurface9* pSurface9 = NULL;
    D3DLOCKED_RECT d3dRect;
    LONG lStride = 0;
    UINT32 uiWidth;
    UINT32 uiLine;

    IMF2DBuffer* p2DBuffer = NULL;

    try {

        if (dwStreamId == 0) {

            IF_FAILED_THROW(hr = pSample->GetSampleTime(&m_llTime));
            IF_FAILED_THROW(hr = pSample->GetSampleDuration(&m_llDuration));
        }

        IF_FAILED_THROW(hr = pSample->GetBufferByIndex(0, &pBuffer));
        IF_FAILED_THROW(hr = pBuffer->QueryInterface(IID_PPV_ARGS(&p2DBuffer)));

        IF_FAILED_THROW(hr = p2DBuffer->Lock2D(&pData, &lStride));

        if (dwStreamId == 0) {

            pSurface9 = m_pRefSurface9;
            uiWidth = m_uiRefWidth;
            uiLine = m_uiRefLine;
        }
        else if (dwStreamId == 1) {

            pSurface9 = m_pSubSurface9;
            //uiWidth = m_uiSubWidth * 4;
            //uiLine = m_uiSubHeight;
            uiWidth = m_uiSubWidth;
            uiLine = m_uiSubLine;
        }

        IF_FAILED_THROW(hr = pSurface9->LockRect(&d3dRect, NULL, 0));

        IF_FAILED_THROW(hr = MFCopyImage((BYTE*)d3dRect.pBits, d3dRect.Pitch, pData, lStride, uiWidth, uiLine));

        IF_FAILED_THROW(hr = pSurface9->UnlockRect());
    }
    catch (HRESULT) {}

    if (pBuffer && pData) {
        LOG_HRESULT(p2DBuffer->Unlock2D());
    }

    SAFE_RELEASE(p2DBuffer);
    SAFE_RELEASE(pBuffer);

    return hr;
}

HRESULT CDxva2Manager::ProcessOutput(IMFSample* pSample) {

    HRESULT hr = S_OK;
    IMFMediaBuffer* pBuffer = NULL;
    IDirect3DSurface9* pSurface = NULL;

    DXVA2_VideoProcessBltParams blt = { 0 };
    RECT rc = { 0, 0, m_uiRefWidth, m_uiRefHeight };
    DXVA2_AYUVSample16 color;
    color.Cr = 0x0000;
    color.Cb = 0xFFFF;
    color.Y = 0x0000;
    color.Alpha = 0xFFFF;

    const UINT EX_COLOR_INFO[][2] =
    {
        // SDTV ITU-R BT.601 YCbCr to driver's optimal RGB range
        { DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_Unknown },
        // SDTV ITU-R BT.601 YCbCr to studio RGB [16...235]
        { DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_16_235 },
        // SDTV ITU-R BT.601 YCbCr to computer RGB [0...255]
        { DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_0_255 },
        // HDTV ITU-R BT.709 YCbCr to driver's optimal RGB range
        { DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_Unknown },
        // HDTV ITU-R BT.709 YCbCr to studio RGB [16...235]
        { DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_16_235 },
        // HDTV ITU-R BT.709 YCbCr to computer RGB [0...255]
        { DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_0_255 }
    };

    DXVA2_Fixed32 ProcAmpValues[4] = { 0 };
    DXVA2_Fixed32 NFilterValues[6] = { 0 };
    DXVA2_Fixed32 DFilterValues[6] = { 0 };

    DXVA2_VideoSample samples[2] = { 0 };
    UINT uiStreamCount = 2;

    blt.TargetFrame = m_llTime;
    blt.TargetRect = rc;
    blt.ConstrictionSize.cx = rc.right;
    blt.ConstrictionSize.cy = rc.bottom;
    blt.BackgroundColor = color;
    blt.DestFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Unknown;
    blt.DestFormat.NominalRange = EX_COLOR_INFO[0][1];
    blt.DestFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_Unknown;
    blt.DestFormat.VideoLighting = DXVA2_VideoLighting_dim;
    blt.DestFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
    blt.DestFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;
    blt.DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
    blt.ProcAmpValues.Brightness = ProcAmpValues[0];
    blt.ProcAmpValues.Contrast.Value = 1;
    blt.ProcAmpValues.Hue = ProcAmpValues[2];
    blt.ProcAmpValues.Saturation.Value = 1;
    blt.Alpha = DXVA2_Fixed32OpaqueAlpha();
    blt.NoiseFilterLuma.Level = NFilterValues[0];
    blt.NoiseFilterLuma.Threshold = NFilterValues[1];
    blt.NoiseFilterLuma.Radius = NFilterValues[2];
    blt.NoiseFilterChroma.Level = NFilterValues[3];
    blt.NoiseFilterChroma.Threshold = NFilterValues[4];
    blt.NoiseFilterChroma.Radius = NFilterValues[5];
    blt.DetailFilterLuma.Level = DFilterValues[0];
    blt.DetailFilterLuma.Threshold = DFilterValues[1];
    blt.DetailFilterLuma.Radius = DFilterValues[2];
    blt.DetailFilterChroma.Level = DFilterValues[3];
    blt.DetailFilterChroma.Threshold = DFilterValues[4];
    blt.DetailFilterChroma.Radius = DFilterValues[5];

    samples[0].Start = m_llTime;
    samples[0].End = m_llTime + m_llDuration;
    samples[0].SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG2;
    samples[0].SampleFormat.NominalRange = DXVA2_NominalRange_16_235;
    samples[0].SampleFormat.VideoTransferMatrix = EX_COLOR_INFO[0][0];
    samples[0].SampleFormat.VideoLighting = DXVA2_VideoLighting_dim;
    samples[0].SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
    samples[0].SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;
    samples[0].SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
    samples[0].SrcSurface = m_pRefSurface9;
    samples[0].SrcRect = rc;
    rc.bottom = m_uiRefHeight / 2;
    samples[0].DstRect = rc;
    samples[0].PlanarAlpha = DXVA2FloatToFixed(float(0xFF) / 0xFF);

    rc.right = m_uiSubWidth;
    rc.bottom = m_uiSubHeight;

    samples[1] = samples[0];
    samples[1].SampleFormat = samples[0].SampleFormat;
    samples[1].SampleFormat.SampleFormat = DXVA2_SampleSubStream;
    samples[1].SrcSurface = m_pSubSurface9;
    samples[1].SrcRect = rc;
    rc.top = m_uiSubHeight / 2;
    samples[1].DstRect = rc;

    try {

        IF_FAILED_THROW(hr = pSample->ConvertToContiguousBuffer(&pBuffer));
        IF_FAILED_THROW(hr = MFGetService(pBuffer, MR_BUFFER_SERVICE, __uuidof(IDirect3DSurface9), (void**)&pSurface));

        IF_FAILED_THROW(hr = m_pVideoProcessor->VideoProcessBlt(pSurface, &blt, samples, uiStreamCount, NULL));
    }
    catch (HRESULT) {}

    SAFE_RELEASE(pBuffer);
    SAFE_RELEASE(pSurface);

    return hr;
}

HRESULT CDxva2Manager::GetDxva2VideoDesc(DXVA2_VideoDesc* dxva2VideoDesc, IMFMediaType* pRefInputType) {

    HRESULT hr;

    IF_FAILED_RETURN(hr = (dxva2VideoDesc == NULL ? E_POINTER : S_OK));
    IF_FAILED_RETURN(hr = (pRefInputType == NULL ? E_POINTER : S_OK));

    D3DFORMAT D3DFormat = D3DFMT_UNKNOWN;
    GUID subtype = { 0 };
    UINT32 uiWidth = 0;
    UINT32 uiHeight = 0;
    UINT32 uiNumerator = 0;
    UINT32 uiDenominator = 0;

    const UINT EX_COLOR_INFO[][2] =
    {
        // SDTV ITU-R BT.601 YCbCr to driver's optimal RGB range
        { DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_Unknown },
        // SDTV ITU-R BT.601 YCbCr to studio RGB [16...235]
        { DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_16_235 },
        // SDTV ITU-R BT.601 YCbCr to computer RGB [0...255]
        { DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_0_255 },
        // HDTV ITU-R BT.709 YCbCr to driver's optimal RGB range
        { DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_Unknown },
        // HDTV ITU-R BT.709 YCbCr to studio RGB [16...235]
        { DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_16_235 },
        // HDTV ITU-R BT.709 YCbCr to computer RGB [0...255]
        { DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_0_255 }
    };

    IF_FAILED_RETURN(hr = pRefInputType->GetGUID(MF_MT_SUBTYPE, &subtype));
    IF_FAILED_RETURN(hr = MFGetAttributeSize(pRefInputType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight));
    IF_FAILED_RETURN(hr = MFGetAttributeRatio(pRefInputType, MF_MT_FRAME_RATE, &uiNumerator, &uiDenominator));

    if (subtype == MFVideoFormat_NV12)
        D3DFormat = (D3DFORMAT)D3DFMT_NV12;
    else
        IF_FAILED_RETURN(hr = E_FAIL);

    dxva2VideoDesc->SampleWidth = uiWidth;
    dxva2VideoDesc->SampleHeight = uiHeight;
    dxva2VideoDesc->SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG2;
    dxva2VideoDesc->SampleFormat.NominalRange = DXVA2_NominalRange_16_235;
    dxva2VideoDesc->SampleFormat.VideoTransferMatrix = EX_COLOR_INFO[0][0];
    dxva2VideoDesc->SampleFormat.VideoLighting = DXVA2_VideoLighting_dim;
    dxva2VideoDesc->SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
    dxva2VideoDesc->SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;
    dxva2VideoDesc->SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
    dxva2VideoDesc->Format = D3DFormat;
    dxva2VideoDesc->InputSampleFreq.Numerator = uiNumerator;
    dxva2VideoDesc->InputSampleFreq.Denominator = uiDenominator;
    dxva2VideoDesc->OutputFrameFreq.Numerator = uiNumerator;
    dxva2VideoDesc->OutputFrameFreq.Denominator = uiDenominator;

    return hr;
}
查看更多
冷血范
5楼-- · 2019-07-24 20:04

You try inject customized code in form of Mixer into the object with IMFMediaSink interface which is written by Microsoft and you have got MF_E_CANNOT_CREATE_SINK - error message which generalize any error into the MediaSink. This error can have hundred reasons. For such situation Microsoft developed a special tool - MFTrace. It logs calls inner of code which is developed by Microsoft. Also, it is impossible recognize the reason of errors, because you have not presented your code. For example - how many stream limits you set into the method GetStreamLimits, or what ID you set into the method GetStreamIDs, or how code process call method AddInputStreams. Only IMFTransform has 23 methods.

You question has so small information that it is impossible recommend something useful.

Regards.

查看更多
登录 后发表回答