说明:
这篇文章简单介绍Windows Moble 自定义DirectShow SampleGrabber 过滤器。
背景:
在我目前的.NET CF项目中需要做一些实时视频分析。但是.NET API仅仅可以取得静态照片或者录音,他不能够访问视频流,这样我可以分析视频流。 所以我选择了DirectShow API,它提供了对对视频流更好的控制,但是他还缺少ISampleGrabber接口,这个接口能使DirectShow库完全在Windows运行。接下来的是自定义一个实现ISampleGrabber接口并能允许开发者进入视频缓冲数据的DirectShow过滤器。
设置你的Visual Studio 项目:
设置Visual Studio 项目前,你需要安装 Windows Mobile SDK, Windows CE 5.0 和 Windows CE 5.0 Platform builder,这些包含BaseClasses库。
写过滤器:
例子中将用到简易版本的TransInPlaceFilter,我写了CSampleGrabber 类,它是使用一些函数继承其他的接口。我加上了RegisterCallback 函数,它能够从客户程序提供指针接口。这个函数将在视频流经过过滤器时被回调,让客户复制数据并作相应处理。
// define the filter class
class CSampleGrabber :
public CTransInPlaceFilter, public ISampleGrabber
{
private:
MANAGEDCALLBACKPROC callback;
long m_Width;
long m_Height;
long m_SampleSize;
long m_Stride;
public:
// instantiation
CSampleGrabber( IUnknown * pOuter, HRESULT * phr, BOOL ModifiesData );
~CSampleGrabber();
static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
// IUnknown
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
// CTransInPlaceFilter
HRESULT CheckInputType(const CMediaType *pmt);
HRESULT SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt);
HRESULT Transform(IMediaSample *pMediaSample);
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) {
return NOERROR;
}
// ISampleGrabber
STDMETHODIMP RegisterCallback(MANAGEDCALLBACKPROC mdelegate);
};
你可以实现任何的过滤接口,下面的是 Transform 和
RegisterCallback 函数。
// Set the client callback
STDMETHODIMP
CSampleGrabber::RegisterCallback( MANAGEDCALLBACKPROC mdelegate )
{
// Set pointer to managed delegate
callback = mdelegate;
return S_OK;
}
// Get the pointer to the raw data and pass it to the applications
HRESULT
CSampleGrabber::Transform(IMediaSample *pMediaSample)
{
long Size = 0;
BYTE *pData;
if ( !pMediaSample )
return E_FAIL;
// Get pointer to the video buffer data
if( FAILED(pMediaSample->GetPointer(&pData)) )
return E_FAIL;
Size = pMediaSample->GetSize();
// invoke managed delegate
if ( callback )
callback(pData,Size);
return S_OK;
}
使用代码:
你可以在DirectShow程序中像使用其它过滤器一样直接使用SampleGrabber filter 。在使用之前注册DLL。
// Create and initialize the SampleGrabber filter
CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void**)&pSampleGrabber );
m_pFilterGraph->AddFilter( pSampleGrabber, FILTERNAME );
// Get a pointer to the ISampleGrabber interface
pSampleGrabber->QueryInterface( IID_ISampleGrabber, (void**)&m_pISampleGrabber );
// Register the client callback
if ( m_pISampleGrabber )
m_pISampleGrabber->RegisterCallback( &CGraphBuilder::OnSampleProcessed );
When the client receives the frame sample, it should copy it to local buffer as soon as possible and return. This allows the filter to carry on and not wait for the client to process the data, which will considerably slow down the whole graph.
You could also make a C++ DLL which creates the filter graph and manages it and calls it through P/Invoke from your .NET CF applications. Creating filter graphs in .NET CF directly should be a bit trickier, as the .NET CF lacks C++. NET support, but maybe possible.
Online References
- A great DirectShow and COM article which goes into detail on writing
DirectShow Transform
filters - Great
DirectShow
information from RadScorpion's Blog - Windows Mobile Developer Center from Microsoft
- Creating a Transform Filter from MSDN
- How To Get Data from a Microsoft DirectShow Filter Graph from MSDN