zoukankan      html  css  js  c++  java
  • DirectShow中写push模式的source filter流程 + 源码(内附具体凝视)

    尽管网上已有非常多关于DirectShow写source filter的资料。只是非常多刚開始学的朋友总说讲的不是非常清楚(可能当中作者省略了很多他觉得简

    单的过程)。读者总希望看到象第一步怎么做,第二步怎么做....这种demo。事实上写你的第一个filter是有一定难度的,仅仅要过了这关以后

    就easy多了。


    因为近期须要自己写一个push推模式的source filter,加上刚激活了Blog,不好意思Blog上没有一篇文章,所以将写这个filter的过程写下来

    ,为了照应刚開始学的朋友,我採用第一步第二步....这种方式尽可能的解说具体,相信你依照这个步骤一定没问题的,对于vc中DirectSho

    w开发环境的配置,这里不做解说。

    以下開始:

    (vc 6.0 + DirectShow 9.0)
    我也记得刚学时候的迷茫。所以会尽量具体每一个过程,所以非常多是sdk的样例我没改动它。没讲的是我提供的源码里面我加有比較具体的凝视

    ,能够配合我提供的源码一起看。

    第一步:建立工程

    File->New->Project选择Win32 Dynamic-Link Library,(因为是个demo,名字我用的Push_Test_01)->Next后选择A simple DLL project(这里

    为了避免自己写DllMain的麻烦,所以没选An empty DLL project)->能够Finish了
    到这里工程建立结束。

    第二步:相关设置和须要加入的文件等操作

    首先将Debug方式改为Release。

    接着Project->Seetings->Link里的Output file

    name从Release/Push_Test_01.dll改为Release/Push_Test_01.ax。

    在工程文件夹下建立一个文本文件。改动名字为Push_Test_01.def。

    将其加入工程:Project->Add to project->Files 选择Push_Test_01.def后

    加入。
    对Push_Test_01.def进行改动。FileView->Source Files 双击Push_Test_01.def后输入:

    LIBRARY     Push_Test_01.ax

    EXPORTS
                DllMain                 PRIVATE
                DllGetClassObject       PRIVATE
                DllCanUnloadNow         PRIVATE
                DllRegisterServer       PRIVATE
                DllUnregisterServer     PRIVATE

    ,确定project->Seetings->link下Object/library modules里面为:

    strmbase.lib msvcrt.lib quartz.lib vfw32.lib winmm.lib kernel32.lib advapi32.lib version.lib largeint.lib user32.lib

    gdi32.lib comctl32.lib ole32.lib olepro32.lib oleaut32.lib uuid.lib

    加入头文件:

    #include <streams.h>
    #include <olectl.h>
    #include <initguid.h>

    生成全球唯一标识,这里这样

    DEFINE_GUID(CLSID_PushTest,
      0xfd501041, 0x8ebe, 0x11ce, 0x81, 0x83, 0x00, 0xaa, 0x00, 0x57, 0x7d, 0xa1);


    第三步:注冊等函数的加入

    首先改动入口函数,并加入注冊和反注冊函数,操作后的内容例如以下:

    //注冊
    STDAPI DllRegisterServer()
    {
        return AMovieDllRegisterServer2(TRUE);
     
    }

    //反注冊
    STDAPI DllUnregisterServer()
    {
        return AMovieDllRegisterServer2(FALSE);
     
    }

    //filter的入口函数
    extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

    BOOL APIENTRY DllMain(HANDLE hModule, 
                          DWORD  dwReason, 
                          LPVOID lpReserved)
    {
     return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
    }

    此时编译会有class CFactoryTemplate没实现等错误,以下我们来实现它。

    加入以下的代码,每一个地方我基本都加了大体意思的凝视:

     

    /**************開始填写注冊信息***************/

    //媒体类型
    const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
    {
        &MEDIATYPE_Video,       // Major type 主类型
      &MEDIASUBTYPE_NULL      // Minor type sub类型,能够为MEDIASUBTYPE_NULL
    };

    //pin的信息
    const AMOVIESETUP_PIN sudOpPin =
    {
      L"Output",              // Pin string name      pin的名字
      FALSE,                  // Is it rendered       输入pin实用,输出pin一般为FALSE
      TRUE,                   // Is it an output      TRUE表示是输出pin。不然是输入pin
      FALSE,                  // Can we have none  能否不实例化
      FALSE,                  // Can we have many  能否创建多个同这样类型的pin
      &CLSID_NULL,            // Connects to filter 连接的filter类
      NULL,                   // Connects to pin      该pin要连接的pin的类
      1,                      // Number of types  该pin支持的媒体类型
      &sudOpPinTypes          // Pin details   该pin的媒体类型的描写叙述

    };
    const AMOVIESETUP_FILTER sudBallax =
    {
        &CLSID_PushTest,    // Filter CLSID   该filter的类标志
      L"Push_Test",       // String name   该filter的名字
      MERIT_DO_NOT_USE,       // Filter merit   该filter的Merit值
      1,                      // Number pins   该filter的pin的数目
      &sudOpPin               // Pin details   该filter的pin的描写叙述
    };

    //创建实例时用,有类。名字等须要的信息
    CFactoryTemplate g_Templates[] = {
     { 
      L"Push_Test"     //filter的名字
       , &CLSID_PushTest    //对象的类标识  
       , PushTestFilter::CreateInstance //创建一个实例用的函数
       , NULL        //
       , &sudBallax      //filter的注冊信息
     }
    };
    int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

    通过上面的凝视。我们看到该filter有一个输出pin。支持Video类型等等信息,不多说了。


    这里主要对PushTestFilter::CreateInstance //创建一个实例用的函数
    说明一下!!PushTestFilter就是我们的filter类!

    。在以下实现它。

    第四步:filter类的实现

    加入新类PushTestFilter。使其继承自CSource。这就是我们的filter类,在这个类里面没有过多的操作,就仅仅有2个函数而已:

    //filter的主类,继承自CSource
    class PushTestFilter : public CSource 
    {
    public:
     // 唯一能创建该类实例的接口
        static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);

    private:
     //仅仅能通过CreateInstance()的调用创建实例
     PushTestFilter(LPUNKNOWN lpunk, HRESULT *phr);
    };

    这里有2点须要注意:

    构造函数PushTestFilter()是private的。不是一般的public!!。!!!!!

    !!
    CreateInstance()函数是static的,因为它不能通过对象来调用!!

    !!

    2个函数的具体实现例如以下:

    //构造函数,注意这里是private属性的,不是public,
    //所以要创建它的实例,仅仅能是通过CreateInstance()函数的方式
    PushTestFilter::PushTestFilter(LPUNKNOWN lpunk, HRESULT *phr):
       CSource(NAME("PushTest"), lpunk, CLSID_PushTest)
    {
     ASSERT(phr);
     CAutoLock cAutoLock(&m_cStateLock);
     
     //m_paStreams是从CSource基类继承来的指针数组。

    因为这个demo我们仅仅
     //有1个pin。所以分配了1个空间
     m_paStreams = (CSourceStream **) new PushTesiPin*[1];
     if(m_paStreams == NULL)
     {
      if(phr)
       *phr = E_OUTOFMEMORY;
      
      return;
     }

     //为刚分配的那个空间付值,这就自己主动给filter加入了一个pin。析构的
     //时候会自己主动释放
     m_paStreams[0] = new PushTesiPin(phr,this,L"Push_Test");
     if(m_paStreams[0] == NULL)
     {
      if(phr)
       *phr = E_OUTOFMEMORY;
      
      return;
     }
    }

    //CreateInstance()该函数是static属性的,因为不能通过对象来调用
    CUnknown * WINAPI PushTestFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
    {
     ASSERT(phr);
     
     //这里调用了private属性的构造函数
     CUnknown *punk = new PushTestFilter(lpunk, phr);
     if(punk == NULL)
     {
      if(phr)
       *phr = E_OUTOFMEMORY;
     }
     return punk;   
    }


    这里的类PushTesiPin就是我们的pin类,在后面要实现!!

    事实上基本的操作是在pin类PushTesiPin里面的。

    第五步:pin类的实现

    加入类PushTesiPin,使其继承自CSourceStream。这里须要重载的函数会多一点!只是没关系。我会一个一
    个的进行说明。

    主要是这3个:

    //因为我们的filter就一种媒体类型,所以重载了GetMediaType(CMediaType *pMediaType)
    //假设有多种类型,就应该重载另外2个函数了。具体參考基类CSourceStream
    HRESULT GetMediaType(CMediaType *pMediaType);

    //这个函数是用来设置Sample大小的,在pin连接成功后会被调用
    HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc,ALLOCATOR_PROPERTIES *pProperties);

    //对Sample数据的填充
    HRESULT FillBuffer(IMediaSample *pms);

    我在源码里面都家了比較具体的凝视,參考源码一起看easy明确。

    事实上这个filter没做别的,就相当与将sdk下的PushSource样例自己再写了一遍,主要是为了说明这个过程。
    到这里相信你应该有个大概的概念了。那么恭喜!

    我也写累了,假设对大家有帮助就找个时间再将写pull拉
    模式的过程也写出来。

  • 相关阅读:
    Metaclass
    Pydantic
    Alembic
    SQLAlchemy
    django2:路由path语法
    Django 学习笔记之模型高级用法
    Flask拾遗总汇1
    Flask中before_request与after_request使用
    Flask 中字典数据返回(jsonify)
    浅析django的abstract,proxy, managed
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6755375.html
Copyright © 2011-2022 走看看