Source Filter flow + source code of write push mode in DirectShow (with detailed notes)

Source: Internet
Author: User

虽然网上已有很多关于DirectShow写source filter的资料,不过很多刚开始学的朋友总说讲的不是很清楚(可能其中作者省略了许多他认为简

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

就容易多了。
由于最近需要自己写一个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);

我在源代码里面都家了比较详细的注释,参考源代码一起看容易明白。

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

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

DirectShow中写push模式的source filter流程 + 源代码(内附详细注释)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.