关于新手 DirectShow写source filter的具体流程

对于vc中DirectShow开发环境的配置,这里不做讲解。下面开始:

(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>


生成全球唯一标识(可以使用cmd命令:guidgen.exe)


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"My OutPutPin",                // 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例子自己再写了一遍,主要是为了说明这个过程,到这里相信你应该有个大概的概念了,那么恭喜!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值