isamplegrabbercb性能优化:让你的程序飞起来!

吉云

今天跟大家唠唠我捣鼓 `ISampleGrabberCB` 的那些事儿,这玩意儿听着就挺唬人,用起来也真不简单,不过搞明白还是挺有意思的。

我接到个任务,需要从摄像头获取视频流,并且要能实时处理每一帧图像。这听起来简单,但实际上坑不少。查半天资料,发现 `DirectShow` 里的 `Sample Grabber` 过滤器是个不错的选择,它能截取视频流里的每一帧数据。而 `ISampleGrabberCB` 接口,就是用来接收这些数据的关键。

我得先搭建好整个 `DirectShow` 的 filter graph。这部分比较繁琐,包括创建 graph manager,添加摄像头 filter,还有最重要的 `Sample Grabber` filter。这一步我参考不少网上的例子,主要是确保摄像头能正常工作,并且数据能顺利地流到 `Sample Grabber`。

isamplegrabbercb性能优化:让你的程序飞起来!

重头戏来,实现 `ISampleGrabberCB` 接口。这接口里有两个方法需要实现:`SampleCB` 和 `BufferCB`。一开始我有点懵,不知道该用哪个。查些资料,`SampleCB` 是每次有新的 sample 到达时被调用,而 `BufferCB` 则是直接操作 buffer 的。考虑到我需要对每一帧图像进行处理,`SampleCB` 更适合我。

我创建一个类,继承 `ISampleGrabberCB`,然后实现 `SampleCB` 方法。在这个方法里,我获取 `IMediaSample` 接口,然后通过 `GetPointer` 方法拿到图像数据的指针。拿到指针后,就可以对图像数据进行各种处理,比如转格式、做一些图像识别等等。

c++

class CSampleGrabberCB : public ISampleGrabberCB

public:

isamplegrabbercb性能优化:让你的程序飞起来!

STDMETHODIMP SampleCB(double SampleTime, IMediaSample pSample)

BYTE pBuffer;

pSample->GetPointer(&pBuffer);

long bufferLen = pSample->GetSize();

// 在这里处理图像数据,比如转格式、图像识别等

isamplegrabbercb性能优化:让你的程序飞起来!

// ...

return S_OK;

STDMETHODIMP BufferCB(double Time, BYTE pBuffer, long bufferLen)

// 这个方法暂时不用

isamplegrabbercb性能优化:让你的程序飞起来!

return S_OK;

STDMETHODIMP QueryInterface(REFIID riid, void ppv) {

if (__uuidof(ISampleGrabberCB) == riid) {

ppv = static_cast(this);

return S_OK;

isamplegrabbercb性能优化:让你的程序飞起来!

return E_NOINTERFACE;

ULONG STDMETHODCALLTYPE AddRef() { return 1; }

ULONG STDMETHODCALLTYPE Release() { return 1; }

isamplegrabbercb性能优化:让你的程序飞起来!

这段代码只是一个简单的框架,实际应用中需要根据具体的需求来填充 `SampleCB` 里的内容。

在实现 `ISampleGrabberCB` 接口之后,我还需要把这个接口设置给 `Sample Grabber` filter。这需要先拿到 `ISampleGrabber` 接口,然后调用 `SetCallback` 方法。

c++

CComPtr m_pSampleGrabber;

CComPtr pSampleGrabberFilter;

isamplegrabbercb性能优化:让你的程序飞起来!

CSampleGrabberCB m_pGrabberCB = new CSampleGrabberCB();

// 创建 Sample Grabber filter

hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void)&pSampleGrabberFilter);

hr = pGraph->AddFilter(pSampleGrabberFilter, L"Sample Grabber");

hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void)&m_pSampleGrabber);

// 设置回调

isamplegrabbercb性能优化:让你的程序飞起来!

hr = m_pSampleGrabber->SetCallback(m_pGrabberCB, 0);

这里需要注意,`SetCallback` 方法的第二个参数是用来控制回调类型的。`0` 表示使用 `SampleCB` 方法,`1` 表示使用 `BufferCB` 方法。

一切就绪后,就可以开始运行 filter graph 。运行过程中,`Sample Grabber` 会不断地截取视频帧,并且调用我实现的 `SampleCB` 方法。这样,我就能实时地获取到每一帧图像的数据,进行各种处理。

实际过程中肯定遇到不少坑。比如,图像格式不正确,导致处理失败;回调函数执行速度太慢,导致视频卡顿等等。这些问题都需要耐心调试和优化。

`ISampleGrabberCB` 是一个强大的接口,可以用来实现各种复杂的视频处理功能。虽然上手有点难度,但只要搞明白原理,就能灵活运用。希望我的实践经历能对大家有所帮助。

isamplegrabbercb性能优化:让你的程序飞起来!

免责声明:由于无法甄别是否为投稿用户创作以及文章的准确性,本站尊重并保护知识产权,根据《信息网络传播权保护条例》,如我们转载的作品侵犯了您的权利,请您通知我们,请将本侵权页面网址发送邮件到qingge@88.com,深感抱歉,我们会做删除处理。

目录[+]