一个最简单的源Filter的编写步骤 转贴
2010-05-24 11:26
288 查看
一个最简单的源Filter的编写步骤
收藏
1.创建一个空的Dll工程,添加5个空文件分别名为:MyOutputPin.h、MySourceFilter.h、MyOutputPin.cpp、MySourceFilter.cpp和MySourceFilter.def。
2.声明两个类,一个是Filter的实现类,一个是输出Pin的实现类,由于是最简单的源Filter,因此Filter只有一个输出Pin。实
现的功能是从本地磁盘读取三个图片文件,轮流显示这三张图片,效果是模拟一个视频流。这两个类的声明代码:
view
plain
copy
to clipboard
?
//MySourceFilter.h
class
CMySourceFilter
//从SDK库中的CSource类派生
: public
CSource
{
public
:
//实例化接口
static
CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk,
HRESULT
*phr);
private
:
//构造函数
CMySourceFilter(LPUNKNOWN lpunk, HRESULT
*phr);
};
//MySourceFilter.h class CMySourceFilter //从SDK库中的CSource类派生 : public CSource { public: //实例化接口 static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr); private: //构造函数 CMySourceFilter(LPUNKNOWN lpunk, HRESULT *phr); };
view
plain
copy
to clipboard
?
//MyOutputPin.h
class
CMyOutputPin
//CSource的派生类都使用
CSourceStream的派生类做为pin
:public
CSourceStream
{
public
:
CMyOutputPin(HRESULT
*phr, CSource *pFilter);
~CMyOutputPin(void
);
//填充样本函数
//参数pMediaSample就是要传递到下一个
Filter输入pin的样本
//把数据填充到pMediaSample中就是这个函数的功能
HRESULT
FillBuffer(IMediaSample *pMediaSample);
//协商每个CMediaSample数据块的大小
HRESULT
DecideBufferSize(IMemAllocator *pIMemAlloc,
ALLOCATOR_PROPERTIES *pProperties);
//获得媒体类型
//在枚举器中枚举支持的媒体类型时调用此函数得到PIN支持的媒体类型
//此函数设置pmt的各个成员,因此,由此函数的内容觉
得PIN支持什么媒体类型
HRESULT
GetMediaType(
int
iPosition, CMediaType *pmt);
//检测是否支持参数传入的媒体类型
HRESULT
CheckMediaType(
const
CMediaType *pMediaType);
//这是质量控制接口,最简单的源Filter不需要质量控制
STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
{
return
E_FAIL;
}
private
:
BYTE
* m_pData[3];
//存储图片数据
int
m_nWidth;
//图片的宽
int
m_nHeight;
//图片的高
int
m_nImageSize;
//图片数据的大小
int
m_nCount;
//计数器,用来切换图片数据的缓冲区
};
//MyOutputPin.h class CMyOutputPin //CSource的派生类都使用CSourceStream的派生类做为pin :public CSourceStream { public: CMyOutputPin(HRESULT *phr, CSource *pFilter); ~CMyOutputPin(void); //填充样本函数 //参数pMediaSample就是要传递到下一个Filter输入pin的样本 //把数据填充到pMediaSample中就是这个函数的功能 HRESULT FillBuffer(IMediaSample *pMediaSample); //协商每个CMediaSample数据块的大小 HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties); //获得媒体类型 //在枚举器中枚举支持的媒体类型时调用此函数得到PIN支持的媒体类型 //此函数设置pmt的各个成员,因此,由此函数的内容觉得PIN支持什么媒体类型 HRESULT GetMediaType(int iPosition, CMediaType *pmt); //检测是否支持参数传入的媒体类型 HRESULT CheckMediaType(const CMediaType *pMediaType); //这是质量控制接口,最简单的源Filter不需要质量控制 STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q) { return E_FAIL; } private: BYTE* m_pData[3];//存储图片数据 int m_nWidth;//图片的宽 int m_nHeight;//图片的高 int m_nImageSize;//图片数据的大小 int m_nCount;//计数器,用来切换图片数据的缓冲区 };
3.实现CMySourceFilter类。这个类只有两个函数需要编写,很简单。
view
plain
copy
to clipboard
?
//CMySourceFilter.cpp
CUnknown* CMySourceFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT
*phr)
{
//实例化函数的工作就是实例化一个源Filter的对象
CUnknown *punk = new
CMySourceFilter(lpunk,phr);
if
(punk == NULL)
{
*phr = E_OUTOFMEMORY;
}
return
punk;
}
CMySourceFilter::CMySourceFilter(LPUNKNOWN lpunk, HRESULT
*phr)
: CSource(L"MyFilter"
,lpunk,CLSID_MyFilter,phr)
{
//创建一个pin的对象实例
//在CSourceStream的构造函数中,会把pin
添加到Filter中
CMyOutputPin* pOutPin = new
CMyOutputPin(phr,
this
);
if
(FAILED(*phr))
{
//因此,在创建失败的时候,要将这个pin从Filter中移除
RemovePin(pOutPin);
pOutPin->Release();
}
}
//CMySourceFilter.cpp CUnknown* CMySourceFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) { //实例化函数的工作就是实例化一个源Filter的对象 CUnknown *punk = new CMySourceFilter(lpunk,phr); if (punk == NULL) { *phr = E_OUTOFMEMORY; } return punk; } CMySourceFilter::CMySourceFilter(LPUNKNOWN lpunk, HRESULT *phr) : CSource(L"MyFilter",lpunk,CLSID_MyFilter,phr) { //创建一个pin的对象实例 //在CSourceStream的构造函数中,会把pin添加到Filter中 CMyOutputPin* pOutPin = new CMyOutputPin(phr,this); if (FAILED(*phr)) { //因此,在创建失败的时候,要将这个pin从Filter中移除 RemovePin(pOutPin); pOutPin->Release(); } }
4.实现CMyOutputPin类,编写Filter主要就是写pin。
view
plain
copy
to clipboard
?
//MyOutputPin.cpp
//构造函数
CMyOutputPin::CMyOutputPin(HRESULT
*phr, CSource *pFilter)
: CSourceStream(L"MyFilter"
,phr,pFilter,L
"Out"
)
, m_nWidth(0)
, m_nHeight(0)
, m_nImageSize(0)
, m_nCount(0)
{
//把图片读到内存中,准备好数据
m_pData[0] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//1.bmp"
,
m_nWidth,m_nHeight,m_nImageSize);
m_pData[1] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//2.bmp"
,
m_nWidth,m_nHeight,m_nImageSize);
m_pData[2] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//3.bmp"
,
m_nWidth,m_nHeight,m_nImageSize);
}
//析构函数
CMyOutputPin::~CMyOutputPin(void
)
{
//释放内存
delete
[]m_pData[0];
delete
[]m_pData[1];
delete
[]m_pData[2];
}
//获取媒体类型
//填充pmt
//最简单的源Filter,因此只支持一种类型,所以
iPosition为0
HRESULT
CMyOutputPin::GetMediaType(
int
iPosition, CMediaType *pmt)
{
CheckPointer(pmt,E_POINTER);
CAutoLock cAutoLock(m_pFilter->pStateLock());
if
(iPosition < 0)
{
return
E_INVALIDARG;
}
// Have we run off the end of types?
if
(iPosition > 0)
{
return
VFW_S_NO_MORE_ITEMS;
}
//给媒体类型申请Format的空间
//填充每一个对象,主要是BITMAPINFOHEADER结
构
VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof
(VIDEOINFO));
if
(NULL == pvi)
return
(E_OUTOFMEMORY);
ZeroMemory(pvi, sizeof
(VIDEOINFO));
pvi->bmiHeader.biBitCount = 24;
pvi->bmiHeader.biHeight = m_nHeight;
pvi->bmiHeader.biWidth = m_nWidth;
pvi->bmiHeader.biSizeImage = m_nImageSize;
pvi->bmiHeader.biPlanes = 1;
pvi->bmiHeader.biSize = sizeof
(BITMAPINFOHEADER);
pvi->bmiHeader.biCompression = BI_RGB;
pvi->bmiHeader.biClrImportant = 0;
SetRectEmpty(&pvi->rcSource);
SetRectEmpty(&pvi->rcTarget);
pmt->SetType(&MEDIATYPE_Video);//设置主媒体类型
pmt->SetSubtype(&MEDIASUBTYPE_RGB24);//设置子媒体类型
pmt->SetFormatType(&FORMAT_VideoInfo);//设置详细格式类型
pmt->SetSampleSize(m_nImageSize);//设置Sample的大小
pmt->SetTemporalCompression(FALSE);
return
NOERROR;
}
//检查媒体类型
//主要是对GetMediaType中设置的各个参数进行比较
HRESULT
CMyOutputPin::CheckMediaType(
const
CMediaType *pMediaType)
{
CheckPointer(pMediaType,E_POINTER);
if
(*(pMediaType->Type()) != MEDIATYPE_Video
|| !(pMediaType->IsFixedSize()))
{
return
E_INVALIDARG;
}
const
GUID *SubType = pMediaType->Subtype();
if
(SubType == NULL)
{
return
E_INVALIDARG;
}
if
(*SubType != MEDIASUBTYPE_RGB24)
{
return
E_INVALIDARG;
}
const
GUID* FormatType = pMediaType->FormatType();
if
(FormatType == NULL)
{
return
E_INVALIDARG;
}
if
(*FormatType != FORMAT_VideoInfo)
{
return
E_INVALIDARG;
}
VIDEOINFO* pvi = (VIDEOINFO*)pMediaType->Format();
if
(pvi == NULL)
{
return
E_INVALIDARG;
}
if
(pvi->bmiHeader.biBitCount != 24 ||
pvi->bmiHeader.biWidth != m_nWidth ||
pvi->bmiHeader.biHeight != m_nHeight)
{
return
E_INVALIDARG;
}
return
S_OK;
}
//协商Sample的大小
HRESULT
CMyOutputPin::DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties)
{
CheckPointer(pIMemAlloc,E_POINTER);
CheckPointer(pProperties,E_POINTER);
CAutoLock cAutoLock(m_pFilter->pStateLock());
HRESULT
hr = NOERROR;
VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();
//确定只有一个buffer
pProperties->cBuffers = 1;
//设置buffer的大小
pProperties->cbBuffer = m_nImageSize;
ASSERT(pProperties->cbBuffer);
//设置属性页
ALLOCATOR_PROPERTIES Actual;
hr = pIMemAlloc->SetProperties(pProperties,&Actual);
if
(FAILED(hr))
{
return
hr;
}
if
(Actual.cbBuffer < pProperties->cbBuffer)
{
return
E_FAIL;
}
ASSERT(Actual.cBuffers == 1);
return
NOERROR;
}
//填充Sample
HRESULT
CMyOutputPin::FillBuffer(IMediaSample *pMediaSample)
{
CheckPointer(pMediaSample,E_POINTER);
BYTE
* pData = NULL;
long
lDataSize = 0;
//获得Sample中存放数据的地址
pMediaSample->GetPointer(&pData);
//取得Sample分配的内存大小
lDataSize = pMediaSample->GetSize();
ZeroMemory(pData,lDataSize);
//把当前需要显示的数据拷贝到内存中
CopyMemory(pData,m_pData[m_nCount%3],m_nImageSize);
//设置时间戳
REFERENCE_TIME start = TS_ONE * m_nCount;
REFERENCE_TIME stop = TS_ONE + start;
pMediaSample->SetTime(&start,&stop);
//准备下一帧数据
m_nCount++;
pMediaSample->SetSyncPoint(TRUE);
return
NOERROR;
}
//MyOutputPin.cpp //构造函数 CMyOutputPin::CMyOutputPin(HRESULT *phr, CSource *pFilter) : CSourceStream(L"MyFilter",phr,pFilter,L"Out") , m_nWidth(0) , m_nHeight(0) , m_nImageSize(0) , m_nCount(0) { //把图片读到内存中,准备好数据 m_pData[0] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//1.bmp", m_nWidth,m_nHeight,m_nImageSize); m_pData[1] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//2.bmp", m_nWidth,m_nHeight,m_nImageSize); m_pData[2] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//3.bmp", m_nWidth,m_nHeight,m_nImageSize); } //析构函数 CMyOutputPin::~CMyOutputPin(void) { //释放内存 delete []m_pData[0]; delete []m_pData[1]; delete []m_pData[2]; } //获取媒体类型 //填充pmt //最简单的源Filter,因此只支持一种类型,所以iPosition为0 HRESULT CMyOutputPin::GetMediaType(int iPosition, CMediaType *pmt) { CheckPointer(pmt,E_POINTER); CAutoLock cAutoLock(m_pFilter->pStateLock()); if(iPosition < 0) { return E_INVALIDARG; } // Have we run off the end of types? if(iPosition > 0) { return VFW_S_NO_MORE_ITEMS; } //给媒体类型申请Format的空间 //填充每一个对象,主要是BITMAPINFOHEADER结构 VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof(VIDEOINFO)); if(NULL == pvi) return(E_OUTOFMEMORY); ZeroMemory(pvi, sizeof(VIDEOINFO)); pvi->bmiHeader.biBitCount = 24; pvi->bmiHeader.biHeight = m_nHeight; pvi->bmiHeader.biWidth = m_nWidth; pvi->bmiHeader.biSizeImage = m_nImageSize; pvi->bmiHeader.biPlanes = 1; pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pvi->bmiHeader.biCompression = BI_RGB; pvi->bmiHeader.biClrImportant = 0; SetRectEmpty(&pvi->rcSource); SetRectEmpty(&pvi->rcTarget); pmt->SetType(&MEDIATYPE_Video);//设置主媒体类型 pmt->SetSubtype(&MEDIASUBTYPE_RGB24);//设置子媒体类型 pmt->SetFormatType(&FORMAT_VideoInfo);//设置详细格式类型 pmt->SetSampleSize(m_nImageSize);//设置Sample的大小 pmt->SetTemporalCompression(FALSE); return NOERROR; } //检查媒体类型 //主要是对GetMediaType中设置的各个参数进行比较 HRESULT CMyOutputPin::CheckMediaType(const CMediaType *pMediaType) { CheckPointer(pMediaType,E_POINTER); if (*(pMediaType->Type()) != MEDIATYPE_Video || !(pMediaType->IsFixedSize())) { return E_INVALIDARG; } const GUID *SubType = pMediaType->Subtype(); if (SubType == NULL) { return E_INVALIDARG; } if (*SubType != MEDIASUBTYPE_RGB24) { return E_INVALIDARG; } const GUID* FormatType = pMediaType->FormatType(); if (FormatType == NULL) { return E_INVALIDARG; } if (*FormatType != FORMAT_VideoInfo) { return E_INVALIDARG; } VIDEOINFO* pvi = (VIDEOINFO*)pMediaType->Format(); if (pvi == NULL) { return E_INVALIDARG; } if (pvi->bmiHeader.biBitCount != 24 || pvi->bmiHeader.biWidth != m_nWidth || pvi->bmiHeader.biHeight != m_nHeight) { return E_INVALIDARG; } return S_OK; } //协商Sample的大小 HRESULT CMyOutputPin::DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties) { CheckPointer(pIMemAlloc,E_POINTER); CheckPointer(pProperties,E_POINTER); CAutoLock cAutoLock(m_pFilter->pStateLock()); HRESULT hr = NOERROR; VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format(); //确定只有一个buffer pProperties->cBuffers = 1; //设置buffer的大小 pProperties->cbBuffer = m_nImageSize; ASSERT(pProperties->cbBuffer); //设置属性页 ALLOCATOR_PROPERTIES Actual; hr = pIMemAlloc->SetProperties(pProperties,&Actual); if(FAILED(hr)) { return hr; } if(Actual.cbBuffer < pProperties->cbBuffer) { return E_FAIL; } ASSERT(Actual.cBuffers == 1); return NOERROR; } //填充Sample HRESULT CMyOutputPin::FillBuffer(IMediaSample *pMediaSample) { CheckPointer(pMediaSample,E_POINTER); BYTE* pData = NULL; long lDataSize = 0; //获得Sample中存放数据的地址 pMediaSample->GetPointer(&pData); //取得Sample分配的内存大小 lDataSize = pMediaSample->GetSize(); ZeroMemory(pData,lDataSize); //把当前需要显示的数据拷贝到内存中 CopyMemory(pData,m_pData[m_nCount%3],m_nImageSize); //设置时间戳 REFERENCE_TIME start = TS_ONE * m_nCount; REFERENCE_TIME stop = TS_ONE + start; pMediaSample->SetTime(&start,&stop); //准备下一帧数据 m_nCount++; pMediaSample->SetSyncPoint(TRUE); return NOERROR; }
LoadBitmapFileToMemory函数的实现
view
plain
copy
to clipboard
?
BYTE
* LoadBitmapFileToMemory(
TCHAR
* pFileName,
int
& nWidth,
int
& nHeight,
int
& nImageDataSize)
{
HBITMAP
hBitmap = (
HBITMAP
)LoadImage( NULL, pFileName, IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
if
(hBitmap == NULL)
return
NULL;
HDC
hDC = CreateCompatibleDC(NULL);
HBITMAP
hOldBitmap = (
HBITMAP
)SelectObject(hDC, hBitmap);
BITMAP bmp;
GetObject(hBitmap, sizeof
(bmp), &bmp);
BITMAPINFOHEADER bih = {0};//位图信息头
bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小
bih.biCompression = BI_RGB;
bih.biHeight = bmp.bmHeight;//高
度
bih.biPlanes = 1;
bih.biSize = sizeof
(BITMAPINFOHEADER);
bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小
bih.biWidth = bmp.bmWidth;//宽度
nImageDataSize = bmp.bmWidthBytes * bmp.bmHeight;
byte * p = new
byte[nImageDataSize];
//申请内存保存位图数据
GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, p,
(LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据
SelectObject(hDC, hOldBitmap);
DeleteObject(hBitmap);
DeleteDC(hDC);
nWidth = bmp.bmWidth;
nHeight = bmp.bmHeight;
return
p;
}
BYTE* LoadBitmapFileToMemory(TCHAR* pFileName, int& nWidth, int& nHeight, int& nImageDataSize) { HBITMAP hBitmap = (HBITMAP)LoadImage( NULL, pFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE ); if(hBitmap == NULL) return NULL; HDC hDC = CreateCompatibleDC(NULL); HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hBitmap); BITMAP bmp; GetObject(hBitmap, sizeof(bmp), &bmp); BITMAPINFOHEADER bih = {0};//位图信息头 bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小 bih.biCompression = BI_RGB; bih.biHeight = bmp.bmHeight;//高度 bih.biPlanes = 1; bih.biSize = sizeof(BITMAPINFOHEADER); bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小 bih.biWidth = bmp.bmWidth;//宽度 nImageDataSize = bmp.bmWidthBytes * bmp.bmHeight; byte * p = new byte[nImageDataSize];//申请内存保存位图数据 GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, p, (LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据 SelectObject(hDC, hOldBitmap); DeleteObject(hBitmap); DeleteDC(hDC); nWidth = bmp.bmWidth; nHeight = bmp.bmHeight; return p; }
5.主要的工作已经做完了,功能已经实现,接下来就是生成Filter。
view
plain
copy
to clipboard
?
//MySourceFilter.h
//动态库工程自然也要有入口函数(固定格式)
extern
"C"
BOOL
WINAPI DllEntryPoint(
HINSTANCE
,
ULONG
,
LPVOID
);
BOOL
APIENTRY DllMain(
HANDLE
hModule,
DWORD
dwReason,
LPVOID
lpReserved)
{
return
DllEntryPoint((
HINSTANCE
)(hModule), dwReason, lpReserved);
}
//组件就少不了注册与注销函数(固定格式)
STDAPI DllRegisterServer()
{
return
AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer()
{
return
AMovieDllRegisterServer2(FALSE);
}
//组件,就要有GUID(通过工具创建)
DEFINE_GUID(CLSID_MyFilter,
0x159386e0, 0x5193, 0x48ac, 0x8a, 0x57, 0x17, 0x88, 0xc7, 0x33, 0x40, 0xc1);
//以下是注册信息的模版,写了注释的地方是我们需要填写的,其他的采用默认
const
AMOVIESETUP_MEDIATYPE sudOpPinTypes =
{
&MEDIATYPE_Video, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
const
AMOVIESETUP_PIN sudOpPin =
{
L"Output"
,
FALSE,
TRUE,
FALSE,
FALSE,
&CLSID_NULL,
NULL,
1,
&sudOpPinTypes };
const
AMOVIESETUP_FILTER sudBallax =
{
&CLSID_MyFilter, // 自定义的GUID
L"MyFilter"
,
// Filter的名字
MERIT_DO_NOT_USE,
1,
&sudOpPin
};
// COM global table of objects in this dll
CFactoryTemplate g_Templates[] = {
{ L"MyFilter"
//Filter的名字
, &CLSID_MyFilter//自定义的
GUID
, CMySourceFilter::CreateInstance//Filter的实例化接口
, NULL
, &sudBallax }
};
int
g_cTemplates =
sizeof
(g_Templates) /
sizeof
(g_Templates[0]);
//MySourceFilter.h //动态库工程自然也要有入口函数(固定格式) extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved); } //组件就少不了注册与注销函数(固定格式) STDAPI DllRegisterServer() { return AMovieDllRegisterServer2(TRUE); } STDAPI DllUnregisterServer() { return AMovieDllRegisterServer2(FALSE); } //组件,就要有GUID(通过工具创建) DEFINE_GUID(CLSID_MyFilter, 0x159386e0, 0x5193, 0x48ac, 0x8a, 0x57, 0x17, 0x88, 0xc7, 0x33, 0x40, 0xc1); //以下是注册信息的模版,写了注释的地方是我们需要填写的,其他的采用默认 const AMOVIESETUP_MEDIATYPE sudOpPinTypes = { &MEDIATYPE_Video, // Major type &MEDIASUBTYPE_NULL // Minor type }; const AMOVIESETUP_PIN sudOpPin = { L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 1, &sudOpPinTypes }; const AMOVIESETUP_FILTER sudBallax = { &CLSID_MyFilter, // 自定义的GUID L"MyFilter", // Filter的名字 MERIT_DO_NOT_USE, 1, &sudOpPin }; // COM global table of objects in this dll CFactoryTemplate g_Templates[] = { { L"MyFilter"//Filter的名字 , &CLSID_MyFilter//自定义的GUID , CMySourceFilter::CreateInstance//Filter的实例化接口 , NULL , &sudBallax } }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
6.MySourceFilter.def文件的内容
view
plain
copy
to clipboard
?
LIBRARY
"MySourceFilter.ax"
EXPORTS
DllMain PRIVATE
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
LIBRARY "MySourceFilter.ax" EXPORTS DllMain PRIVATE DllGetClassObject PRIVATE DllCanUnloadNow PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE
7.注意
1)包含头文件 #include <initguid.h>,否则有可能提示 error LNK2001: 无法解析的外部符号
_CLSID_MyFilter
2)包含导出库#pragma comment(lib, "winmm")
3)包含导入库#pragma comment(lib, "strmbase.lib"),Debug下包含#pragma
comment(lib, "strmbasd.lib")
8.大功告成。调用regsvr32注册Filter。使用GraphEdit调试Filter。(VS2005)
在工程的属性中选择调试,在命令中填入GraphEdit的完整路径,把Filter的工程作为启动项。按下F5,在运行的GraphEdit中选
择我们的Filter,Render pin,就可以看到一条完整的链路,然后run,效果出来了,三幅图片轮流显示在窗口中。
相关文章推荐
- 一个最简单的源Filter的编写步骤 转贴
- 一个最简单的源Filter的编写步骤 转贴
- 一个最简单的源Filter的编写步骤
- WebService(一):详细步骤带你编写第一个简单的CXF框架实现WebService程序
- DirectShow基础编程 最简单的源Filter的编写步骤
- 1.编写一个简单的C语言程序:根据输入的两个整数求平均值并且在终端输出,通过gcc编译器得到它的汇编程序文件。 2.编写一个C语言程序:打印输出所有“水仙花数”,用gdb调试程序(给出步骤)。所谓“
- DirectShow基础编程 最简单的源Filter的编写步骤
- 1.编写一个简单的C语言程序:根据输入的两个整数求平均值并且在终端输出,通过gcc编译器得到它的汇编程序文件。 2.编写一个C语言程序:打印输出所有“水仙花数”,用gdb调试程序(给出步骤)。所谓“
- 如何用FFmpeg编写一个简单播放器详细步骤介绍
- DirectShow基础编程 最简单的源Filter的编写步骤
- 35-002-2 struts前期之 struts开发步骤 编写一个简单struts框架实现
- 如何用FFmpeg编写一个简单播放器详细步骤介绍(转载)
- DirectShow基础编程 最简单的源Filter的编写步骤
- 第一次使用linux并编写了一个dump mysql的程序,记录下简单的步骤
- 如何创建一个简单的JAVA存储过程?[转贴]
- 利用C#编写一个简单的抓网页应用程序
- OSGI实战教程【Spring DM】编写一个简单的Bundle组件
- 编写一个简单的控制台通讯录
- 用Python编写一个简单的Http Server
- 03-一个简单的注册页面---使用线性布局方式编写