USB应用层开发
+ -

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

2021-08-30 369 1

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

HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

Directshow获取颜色空间分辨率
void GetColorSpaceResolution(){ HRESULT hr; AM_MEDIA_TYPE *pmt = NULL; VIDEOINFOHEADER *pvi = NULL; VIDEO_STREAM_CONFIG_CAPS scc; IAMSt......
DirectShow时钟时间
DirectShow定义了两个相关的时钟时间:参考时间和流时间。参考时间是参考时钟返回的绝对时间。(见参考时钟。)流时间是相对于图形上次开始运行的时间定义的。图形运行时,流时间等于参考时间减去开始时间。图形暂停时,流时间保持在暂停时的流时间。寻道操作后,流时间重置为零。图形停止时,流时间未定义。当媒......
DirectShow 事件产生
要处理DirectShow事件,应用程序需要一种方法来确定事件何时在队列中等待。过滤器图形管理器提供了两种方法:窗口通知:每当出现新事件时,过滤器图形管理器就会向应用程序窗口发送用户定义的窗口消息。事件信号:如果队列中有DirectShow事件,Filter Graph Manager将向Windo......
DirectShow 图形过滤(Filter)管理器介绍
Filter Graph Manager也是一个COM组件,它是DirectShow的控制中心,它控制Filter的运行。它有以下几个功能:协调各个Filter的状态。Filter有运行,暂停,停止三种状态,在Filter Graph中,各个Filter的状态必须协调一到,否则会引起冲突。Filte......
DirectShow播放UVC设备第二路码流方法
双码流播放Graphi图如上。双码流视频设备有两路捕获输出pin, RenderStream函数只会连接第一路pin,要播放第二路码流需要手动获取第二路pin,然后去连接解码器,再手动连接render,就可以显示了。示例代码// m_pGB 是 IGraphBuilder对象// m_pBF......
常用图像像素格式 NV12、NV2、I420、YV12、YUYV
常用图像像素格式 RGB 和 YUV,像素格式描述了像素数据存储所用的格式,定义了像素在内存中的编码方式。RGB 和 YUV 为两种经常使用的像素格式。1.RGB 格式一般较为熟悉,RGB图像具有三个通道 R、G、B,分别对应红、绿、蓝三个分量,由三个分量的值决定颜色;这三种颜色称为 三原色,将它......
DirectShow 体系结构
DirectShow技术是建立在DirectDraw和DirectSound组件基础之上的,它通过DirectDraw对显卡进行控制以显示视频,通过DirectSound对声卡进行控制以播放声音。DirectShow的体系结构如下图所示:DirectShow 位于应用层中。它使用一种叫 Filter......
DirectShow实现视频的实时显示并抓图,可以设置视频参数
DirectShow抓图其实是使用IBasicVideo(IID_IBasicVideo)接口获取数据源,进行存储即可。IGraphBuilder* m_pGraphBuild = NULL;hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_......
DirectShow 过滤器之间数据交互
过滤器通过pin连接,连接的两个PIN在在上游过滤器叫做输出pin,下游过滤器的叫做输入pin。数据从上游过滤器传递给下游过滤器通过这两个上游过滤器的输出pin到下游过滤器的输出pin实现。通常,下游过滤器通过IMemInputPin::Receive来接收来自上游过滤器输出pin发送的数据。上下游......
DirectShow数据流
本节介绍DirectShow的数据的工作方式进行介绍。通过滤器之间数据交互一节可知,数据是存在buffer中的。而每个buffer都由一个名为media sample的COM对象包装,该对象实现了IMediaSample接口。Sample由另一种类型的对象(称为分配器)创建的,它由IMemAlloc......
DirectShow 简介
DirectShow是微软Windows操作系统平台关于多媒体架构的一套API接口。使用DirectShow,应用程序可以执行高质量的视频和音频播放或采集。DirectShow提供高质量的多媒体流捕获和播放。它支持多种格式,包括Advanced Systems Format(ASF)、Motion ......
DirectShow Samples和Allocators
在看本节前,我们首先明确2个概念。通过前面的章节可知:Samples是DirectShow各过滤器之间传输的数据的封包。Allocators是用于创建Samples的分配器。本节将详细介绍Allocators和Sample的原理。当一个过滤器通过其输出管脚将多媒体数据传输给另一个过滤器(通过其输入管......
DirectShow 接收事件
过滤器图形管理器公开了三个支持事件通知的接口。IMediaEventSink包含筛选器发布事件的方法。IMediaEvent包含应用程序检索事件的方法。IMediaEventEx继承并扩展IMediaEvent接口。过滤器通过调用Filter Graph Manager上的IMediaEventSi......
DirectShow数据传输协议
DirectShow数据传输协议定义为了进行数据交换,DirectShow的过滤器(filter)必须支持相关的数据传输协议,这个传输的协议叫做transports。当2个图形过滤器的pin相连接后,它们必须支持相同的transports,除非它们进行数据交换。通常,传输要求其中一个管脚支持特定接口......
DirectShow实时源
实时源(也称为推送push源)实时接收数据。示例包括视频捕获和网络广播。通常,活动源无法控制数据到达的速率。如果满足以下任一条件,则筛选器被视为实时源:过滤器从IAMFilterMiscFlags::GetMiscFlags方法返回AM_FILTER_MISC_FLAGS_IS_SOURCE标志,并......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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