做的这个directshow的filter属于transform filter。在其间,参考了,directshow的帮助文档,一本外文的介绍directshow的书(这本书不错,里面的代码,虽然感觉有copy directshow帮助文档的成分,但是,讲的挺不错),还有vc知识库中的两篇文章了,这两篇文章也写得挺好的。如果当初我没有看,我想会走不少弯 路。
要写directshow的transform filter 已经准备了好久了。曾经用过directshow,不过里面的也就是用现成的filter组成一个filter graph,然后run,就可以了。把自己写filter看作挺难的事情。现在发现,其实写transform filter不难,当然,也只是像我这样简单的。但是,处理的速度确实是问题。
首先,directshow filter是符合com组件规范的,也就是,其是一个com组件,要符合com的规范,需要实现一些函数的,不过,已经有不少的基类了,只需要继承就可 以了,这样,对com组件所涉及的知识就少了很多。在编写directshow filter时,只要找准了要继承的基类,然后,实现里面的虚函数等等,写上自己的控制代码,就可以了。
下面先简单的给出一些源代码和说明,具体的解释,以后会做。
这个简单的transform filter由三个文件组成:
1。ToGrayFilter.def:由于filter是个基于dll的com组件,所以一般的filter要实现几个入口函数。要导出dll中 的函数有两种方法:一种是在定义函数时使用导出关键字__declspec(dllexport),也就是在.h文件中定义函数如下:
extern “C“ __declspec(dllexport) BOOL DllRegisterServer;等等;第二种方法是使用模块定义文件,这也是我在这里用的方法。
//ToGrayFilter.def
LIBRARY ToGrayFilter.ax
EXPORTS
DllMain PRIVATE //dll的入口函数,directshow中实现的是dllEntryPoint
DllGetClassObject PRIVATE //用于获得类工厂指针
DllCanUnloadNow PRIVATE //系统空闲时会调用这个函数,确定是否可以卸载DLL
DllRegisterServer PRIVATE //将com组件注册到注册表中
DllUnregisterServer PRIVATE //删除注册表中的com组件的注册信息
上面的函数是作为一个典型的自注册com组件dll所必需的5个导出函数。
2。ToGrayFilter.h
在这个文件中声明了一个c++类,这个类是从directshow中的一个用于方便用户编写filter的基类中继承的。
//ToGrayFilter.h
//
#ifndef TOGRAYFILTER_H_
#define TOGRAYFILTER_H_
//
// {5F2265B1-A841-4eb7-871F-5556436042AC}
DEFINE_GUID(CLSID_ToGrayFilter,
0x5f2265b1, 0xa841, 0x4eb7, 0x87, 0x1f, 0x55, 0x56, 0x43, 0x60, 0x42, 0xac);
class CToGrayFilter:public CTransformFilter
{
public:
CToGrayFilter(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr); //constructor
~CToGrayFilter(); //destructor
public:
// Static object-creation method (for the class factory) //必须有的
//
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr);
public:
//implement the base filter 's method,下面5个函数是CTranseformFilter的虚函数,必须实现了的
//
HRESULT CheckInputType(const CMediaType *pmtIn);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
HRESULT CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut);
HRESULT DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProp);
HRESULT Transform(IMediaSample *pSource,IMediaSample *pDest);
//this method is also in the base filter class,but in the base class it does noting,
//implement here just want to get m_VihIn and m_VihOut
//
HRESULT SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt);
private:
//my own process method,这是我自己的处理函数:),在Transform这个函数中调用的
//
HRESULT ToGray(BYTE *pbInput,BYTE *pbOutput);
//a help method ,just copy from helper document,这个函数,最终没有在这个filter中用,因为不知道为何,
//感觉有些问题,按理说是不应该这样的。最后是自己直接操作了
void GetVideoInfoParameters(
const VIDEOINFOHEADER *pvih, // Pointer to the format header.
BYTE * const pbData, // Pointer to the first address in the buffer.
bool bYuv, // Is this a YUV format? (true = YUV, false = RGB)
DWORD *pdwWidth, // Returns the width in pixels.
DWORD *pdwHeight, // Returns the height in pixels.
LONG *plStrideInBytes, // Add this to a row to get the new row down.
BYTE **ppbTop // Returns a pointer to the first byte in the
// top row of pixels.
);
VIDEOINFOHEADER m_VihIn; // Holds the current video format (input),可以把每一帧图像当作bmp位图
VIDEOINFOHEADER m_VihOut; // Holds the current video format (output)
//the imformation about every picture,put here just for speed
//
DWORD m_bytePerLine;//the real numbers of bits in one line,just for handy
int m_Width;//the width of the bitmap,to use it ,just handy
int m_Height;//the height of the bitmap
};
#endif
3。ToGrayFilter.cpp
-
- #include "stdafx.h"
-
-
- #include "streams.h" //用到了filter的基类,就要包含这个头文件的
- #include <initguid.h> //
- #include <tchar.h>
- #include <stdio.h>
-
- #include "ToGrayFilter.h"
-
- #pragma warning(disable:4715)
-
-
-
- CToGrayFilter:: CToGrayFilter(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr):
- CTransformFilter(pName, pUnk, CLSID_ToGrayFilter)
- {
- }
-
- CToGrayFilter::~CToGrayFilter()
- {
- }
-
-
-
- HRESULT CToGrayFilter::CheckInputType(const CMediaType *pmtIn)
- {
- if ((pmtIn->majortype != MEDIATYPE_Video) ||
- (pmtIn->subtype != MEDIASUBTYPE_RGB24) ||
- (pmtIn->formattype != FORMAT_VideoInfo) ||
- (pmtIn->cbFormat < sizeof(VIDEOINFOHEADER)))
- {
- return VFW_E_TYPE_NOT_ACCEPTED;
- }
-
- VIDEOINFOHEADER *pVih =
- reinterpret_cast<VIDEOINFOHEADER*>(pmtIn->pbFormat);
-
-
-
- return S_OK;
-
- }
-
-
-
-
-
- HRESULT CToGrayFilter::GetMediaType(int iPosition, CMediaType *pMediaType)
- {
-
- ASSERT(m_pInput->IsConnected());
-
-
- if (iPosition < 0)
- {
- return E_INVALIDARG;
- }
- else if (iPosition == 0)
- {
-
- return m_pInput->ConnectionMediaType(pMediaType);
- }
- return VFW_S_NO_MORE_ITEMS;
-
- }
-
-
-
-
-
- HRESULT CToGrayFilter::CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut)
- {
-
-
- if (mtOut->majortype != MEDIATYPE_Video)
- {
- return VFW_E_TYPE_NOT_ACCEPTED;
- }
-
-
-
-
-
-
- if (mtIn->subtype != mtOut->subtype)
- {
- return VFW_E_TYPE_NOT_ACCEPTED;
- }
- if ((mtOut->formattype != FORMAT_VideoInfo) ||
- (mtOut->cbFormat < sizeof(VIDEOINFOHEADER)))
- {
- return VFW_E_TYPE_NOT_ACCEPTED;
- }
-
-
-
- ASSERT(mtIn->formattype == FORMAT_VideoInfo);
- BITMAPINFOHEADER *pBmiOut = HEADER(mtOut->pbFormat);
- BITMAPINFOHEADER *pBmiIn = HEADER(mtIn->pbFormat);
-
- if ((pBmiOut->biWidth <= pBmiIn->biWidth) &&
- (pBmiOut->biHeight == abs(pBmiIn->biHeight)))
- {
- return S_OK;
- }
- return VFW_E_TYPE_NOT_ACCEPTED;
-
- }
-
-
-
-
-
-
-
- HRESULT CToGrayFilter::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProp)
- {
-
-
- if (!m_pInput->IsConnected())
- {
- return E_UNEXPECTED;
- }
-
-
-
-
-
-
- ALLOCATOR_PROPERTIES InputProps;
-
- IMemAllocator *pAllocInput = 0;
- HRESULT hr = m_pInput->GetAllocator(&pAllocInput);
-
- if (FAILED(hr))
- {
- return hr;
- }
-
-
- hr = pAllocInput->GetProperties(&InputProps);
- pAllocInput->Release();
-
- if (FAILED(hr))
- {
- return hr;
- }
-
-
- if (pProp->cbAlign == 0)
- {
- pProp->cbAlign = 1;
- }
-
-
- if (pProp->cbBuffer == 0)
- {
- pProp->cBuffers = 1;
- }
-
-
-
- pProp->cbBuffer = max(InputProps.cbBuffer, pProp->cbBuffer);
-
-
- ALLOCATOR_PROPERTIES Actual;
- hr = pAlloc->SetProperties(pProp, &Actual);
- if (FAILED(hr))
- {
- return hr;
- }
-
- }
-
- HRESULT CToGrayFilter::Transform(IMediaSample *pSource,IMediaSample *pDest)
- {
-
-
- BYTE *pBufferIn, *pBufferOut;
- HRESULT hr;
- hr = pSource->GetPointer(&pBufferIn);
- if (FAILED(hr))
- {
- return hr;
- }
- hr = pDest->GetPointer(&pBufferOut);
- if (FAILED(hr))
- {
- return hr;
- }
-
-
-
- ToGray(pBufferIn,pBufferOut);
-
- }
-
-
-
-
-
-
- HRESULT CToGrayFilter::SetMediaType(PIN_DIRECTION direction,
- const CMediaType *pmt)
- {
- if (direction == PINDIR_INPUT)
- {
- ASSERT(pmt->formattype == FORMAT_VideoInfo);
- VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmt->pbFormat;
-
-
-
-
-
-
-
- CopyMemory(&m_VihIn, pVih, sizeof(VIDEOINFOHEADER));
-
- }
- else
- {
- ASSERT(direction == PINDIR_OUTPUT);
- ASSERT(pmt->formattype == FORMAT_VideoInfo);
- VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmt->pbFormat;
-
- CopyMemory(&m_VihOut, pVih, sizeof(VIDEOINFOHEADER));
- }
-
-
-
-
-
-
- m_Width=m_VihIn.bmiHeader.biWidth;
- m_Height=m_VihIn.bmiHeader.biHeight;
- m_bytePerLine=(24*m_Width+31)/32*4;
-
-
- return S_OK;
- }
-
-
-
-
- HRESULT CToGrayFilter::ToGray(BYTE *pbInput,BYTE *pbOutput)
- {
- DWORD dwWidth, dwHeight;
- DWORD dwWidthOut, dwHeightOut;
- LONG lStrideIn, lStrideOut;
- BYTE *pbSource, *pbTarget;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BYTE rColor,gColor,bColor,changeColor;
- for (int i=0;i<m_Height;i++)
- {
- for (int j=0;j<m_Width;j++)
- {
- rColor=*(pbInput+(m_Height-i-1)*m_bytePerLine+j*3);
- gColor=*(pbInput+(m_Height-i-1)*m_bytePerLine+j*3+1);
- bColor=*(pbInput+(m_Height-i-1)*m_bytePerLine+j*3+2);
-
- changeColor=(rColor+gColor+bColor)/3;
-
- *(pbOutput+(m_Height-i-1)*m_bytePerLine+j*3)=changeColor;
- *(pbOutput+(m_Height-i-1)*m_bytePerLine+j*3+1)=changeColor;
- *(pbOutput+(m_Height-i-1)*m_bytePerLine+j*3+2)=changeColor;
- }
- }
-
- return S_OK;
-
- }
-
-
-
- void CToGrayFilter::GetVideoInfoParameters(
- const VIDEOINFOHEADER *pvih,
- BYTE * const pbData,
- bool bYuv,
- DWORD *pdwWidth,
- DWORD *pdwHeight,
- LONG *plStrideInBytes,
- BYTE **ppbTop
-
- )
- {
- LONG lStride;
-
-
-
- if ((pvih->bmiHeader.biBitCount != 0) &&
- (0 == (7 & pvih->bmiHeader.biBitCount)))
- {
- lStride = (pvih->bmiHeader.biWidth * (pvih->bmiHeader.biBitCount / 8) + 3) & ~3;
- }
- else
- {
- lStride = pvih->bmiHeader.biWidth;
- }
-
-
- if (IsRectEmpty(&pvih->rcTarget))
- {
- *pdwWidth = (DWORD)pvih->bmiHeader.biWidth;
- *pdwHeight = (DWORD)(abs(pvih->bmiHeader.biHeight));
-
- if (pvih->bmiHeader.biHeight < 0 || bYuv)
- {
- *plStrideInBytes = lStride;
- *ppbTop = pbData;
- }
- else
- {
- *plStrideInBytes = -lStride;
-
- *ppbTop = pbData + lStride * (*pdwHeight - 1);
- }
- }
- else
- {
- *pdwWidth = (DWORD)(pvih->rcTarget.right - pvih->rcTarget.left);
- *pdwHeight = (DWORD)(pvih->rcTarget.bottom - pvih->rcTarget.top);
-
- if (pvih->bmiHeader.biHeight < 0 || bYuv)
- {
-
-
- *plStrideInBytes = lStride;
- *ppbTop = pbData +
- lStride * pvih->rcTarget.top +
- (pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8;
- }
- else
- {
- *plStrideInBytes = -lStride;
- *ppbTop = pbData +
- lStride * (pvih->bmiHeader.biHeight - pvih->rcTarget.top - 1) +
- (pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8;
- }
- }
- }
-
-
-
-
-
- CUnknown* WINAPI CToGrayFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
- {
- CToGrayFilter *pFilter = new CToGrayFilter(NAME("To Gray Filter"), pUnk, pHr);
- if (pFilter== NULL)
- {
- *pHr = E_OUTOFMEMORY;
- }
- return pFilter;
- }
-
-
-
-
-
- extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE ,DWORD,LPVOID );
-
- BOOL APIENTRY DllMain(HANDLE hModule,DWORD dwRes,LPVOID pv)
- {
- return DllEntryPoint((HINSTANCE)hModule,dwRes,pv);
- }
-
- HRESULT WINAPI DllRegisterServer()
- {
- return AMovieDllRegisterServer2(TRUE);
- }
- HRESULT WINAPI DllUnregisterServer()
- {
- return AMovieDllRegisterServer2(FALSE);
- }
-
-
-
- AMOVIESETUP_FILTER FilterInfo =
- {
- &CLSID_ToGrayFilter,
- L"To Gray Filter",
- MERIT_DO_NOT_USE,
- 0,
- NULL
- };
-
-
- CFactoryTemplate g_Templates[]={
- {
- L"To Gray Filter",
- &CLSID_ToGrayFilter,
- CToGrayFilter::CreateInstance,
- 0,
- &FilterInfo,
- }
-
- };
- int g_cTemplates=sizeof(g_Templates)/sizeof(g_Templates[0]);
上面就是我的程序的所有源代码。这只是一个示例的程序而已,里面有好多东西,其实将来写从CTransformFilter继承的 transform filter是完全可以重复使用的,也就是里面的很多东西都差不多都会是这样。代码简单,真正自己的实现只是一个函数而已,里面只是得到像素的值,然后进 行转换。也就是说,transformfilter有一个架子,不同的只是对像素的操作而已。
现在匆匆收场了,其实还有好多没有提到的地方,但是现在心情突然不好了,以后再补充吧。
文章:来源
(mengaim_cn) |