DirectShow使用过滤器支持NV12数据格式

7 0 2021-07-13 本文地址:http://www.usbzh.com/fun/detail-38.html

DirectShow默认是不支持NV12,H264等非原生态数据格式的,为了支持这些非原生态的格式,微软的DirectShow使用过滤器来实现。具体原理就是在对收到的不支持的数据格式进行转码,这样就可以渲染了。

说明:本段代码来自USB中文网技术交流群,感谢临江仙的分享!

class CFormatConvertFilter : public CTransformFilter
{
private:
 CFormatConvertFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);

public:
 static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);   

 HRESULT CheckInputType(const CMediaType *mtIn);
 HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
 HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);
 HRESULT DecideBufferSize(IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop);
 HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);

    void SetConvertFmt(int fmt);
    BOOL IsConvertHEVC();
    BOOL IsConvertNV12();

protected:
    int m_nConvertFmt;
};

HRESULT ConnectGraphFilters(BOOL Capture)
{

    HRESULT hr = NOERROR;

    CFormatConvertFilter *cf = NULL;
    AM_MEDIA_TYPE *pmt;


    gcap.pVSC->GetFormat(&pmt);
    if (pmt->subtype == MEDIASUBTYPE_NV12)
    {
        cf = (CFormatConvertFilter *)CFormatConvertFilter::CreateInstance(NULL, &hr);
         cf->SetConvertFmt(FormatConvert_NV12);
        gcap.pFg->AddFilter(cf, L"NV12 Convert");
    }
    else if (gcap.capH265 || pmt->subtype == subtype_h265)
    {
        cf = (CFormatConvertFilter *)CFormatConvertFilter::CreateInstance(NULL, &hr);
        cf->SetConvertFmt(FormatConvert_HEVC);
        gcap.pFg->AddFilter(cf, L"HEVC Convert");
    }
    DeleteMediaType(pmt);



    IBaseFilter *pSmartTee = NULL;
    CoCreateInstance(CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pSmartTee);
    gcap.pFg->AddFilter(pSmartTee, L"SmartTee");


    IBaseFilter *pRender = NULL;
    //CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pRender);
    //CoCreateInstance(CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter,(void **)&pRender );

    CoCreateInstance(CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pRender);
    gcap.pFg->AddFilter(pRender, L"Video Render");


    IPin *pinCapOutput = gcap.capPin;


    IPin *pinSTInput = NULL;
    IPin *pinSTPreviewOut = NULL;
    IPin *pinFormatInput = NULL;
    IPin *pinFormatOutput = NULL;
    IPin *pinRenderInput = NULL;
    IPin *pinGrabIn = NULL;
    IPin *pinGrabOut = NULL;

    gcap.pBuilder->FindPin(pSmartTee, PINDIR_INPUT, NULL,
        NULL, FALSE, 0, &pinSTInput);;

    pSmartTee->FindPin(L"Preview", &pinSTPreviewOut);



    gcap.pBuilder->FindPin(pRender, PINDIR_INPUT, NULL,
        NULL, FALSE, 0, &pinRenderInput);





    if (!Capture)
    {
        CSimpleFilter *pGrab = (CSimpleFilter *)CSimpleFilter::CreateInstance(NULL, &hr);
        pGrab->SetCallBack(GrabCallBack);
        gcap.pFg->AddFilter(pGrab, L"Grab");

        gcap.pBuilder->FindPin((IBaseFilter *)pGrab, PINDIR_INPUT, NULL,
            NULL, FALSE, 0, &pinGrabIn);

        gcap.pBuilder->FindPin((IBaseFilter *)pGrab, PINDIR_OUTPUT, NULL,
            NULL, FALSE, 0, &pinGrabOut);

        gcap.pFg->Connect(pinCapOutput, pinGrabIn);
        gcap.pFg->Connect(pinGrabOut, pinSTInput);
    }
    else
    {
        gcap.pFg->Connect(pinCapOutput, pinSTInput);

    }





   // hr = gcap.pFg->Connect(pinSTPreviewOut, pinGrabIn);

    if (cf)
    {
        gcap.pBuilder->FindPin((IBaseFilter *)cf, PINDIR_INPUT, NULL,
            NULL, FALSE, 0, &pinFormatInput);

        gcap.pBuilder->FindPin((IBaseFilter *)cf, PINDIR_OUTPUT, NULL,
            NULL, FALSE, 0, &pinFormatOutput);

        gcap.pFg->Connect(pinSTPreviewOut, pinFormatInput);

        hr = gcap.pFg->Connect(pinFormatOutput, pinRenderInput);
    }
    else
    {
        hr = gcap.pFg->Connect(pinSTPreviewOut, pinRenderInput);
    }


    if (Capture)
    {
        IPin *pinSTCapOut = NULL;
        IPin *pinMuxIn = NULL;

         pSmartTee->FindPin(L"Capture", &pinSTCapOut);
         gcap.pBuilder->FindPin(gcap.pRender, PINDIR_INPUT, NULL,
             NULL, FALSE, 0, &pinMuxIn);;

         hr = gcap.pFg->Connect(pinSTCapOut, pinMuxIn);

         SAFE_RELEASE(pinSTCapOut);
         SAFE_RELEASE(pinMuxIn);
    }

    //SAFE_RELEASE(pGrab);
    SAFE_RELEASE(pinGrabIn);
    SAFE_RELEASE(pinGrabOut);

    SAFE_RELEASE(pSmartTee);
    SAFE_RELEASE(pRender);
    SAFE_RELEASE(pinSTInput);
    SAFE_RELEASE(pinSTPreviewOut);
    SAFE_RELEASE(pinFormatInput);
    SAFE_RELEASE(pinFormatOutput);
    SAFE_RELEASE(pinRenderInput);

    gcap.fPreviewFaked = TRUE;
    return S_OK;
}

参考阅读:

常用图像像素格式 NV12、NV2、I420、YV12、YUYV http://www.usbzh.com/article/detail-214.html

取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!