http://blog.csdn.net/bwmwm/archive/2010/04/08/5463852.aspx
1.创建一个空的Dll工程,添加5个空文件分别名为:MyOutputPin.h、MySourceFilter.h、MyOutputPin.cpp、MySourceFilter.cpp和MySourceFilter.def。
2.声明两个类,一个是Filter的实现类,一个是输出Pin的实现类,由于是最简单的源Filter,因此Filter只有一个输出Pin。实现的功能是从本地磁盘读取三个图片文件,轮流显示这三张图片,效果是模拟一个视频流。这两个类的声明代码:
view plaincopy to clipboardprint?
//MySourceFilter.h
class CMySourceFilter
//从SDK库中的CSource类派生
: public CSource
{
public:
//实例化接口
static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
private:
//构造函数
CMySourceFilter(LPUNKNOWN lpunk, HRESULT *phr);
};
//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类。这个类只有两个函数需要编写,很简单。
//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。
//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;
}
5.主要的工作已经做完了,功能已经实现,接下来就是生成Filter。
//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 plaincopy to clipboardprint?
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,效果出来了,三幅图片轮流显示在窗口中。
注:完整代码下载:http://d.download.csdn.net/down/2218035/bwmwm
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bwmwm/archive/2010/04/08/5463852.aspx