iSampleGrabberCB是DirectShow中用于抓取音视频数据的接口,该接口主要用于捕获音视频流中的帧数据,提供给应用程序进行二次处理或存储。在本文中,我们将学习如何使用iSampleGrabberCB接口捕获音视频数据,在应用程序中进行处理。
1. 接口介绍
iSampleGrabberCB是一种回调接口,它是DirectShow中ISampleGrabber的回调接口。ISampleGrabber是一个DirectShow接口,它提供在我们的应用程序中捕获音视频帧的方法。ISampleGrabber是一个com接口,可以通过CoCreateInstance函数得到。
2. 接口定义
接口定义如下:
```
interface ISampleGrabberCB : public IUnknown
{
virtual STDMETHODIMP SampleCB(double SampleTime, IMediaSample *pSample) = 0;
virtual STDMETHODIMP BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen) = 0;
};
```
SampleCB用于传递IMediaSample对象,即媒体帧数据。BufferCB用于传递指向缓冲区的指针和缓冲区长度。
3. 创建ISampleGrabber接口
我们可以使用CoCreateInstance函数创建ISampleGrabber接口,如下所示:
```C++
// Step 1: Create a Sample Grabber
IBaseFilter* pGrabberF = NULL;
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**) &pGrabberF);
if (FAILED(hr))
{
TRACE( "ERROR: could not create Sample Grabber object\n");
return hr;
}
ISampleGrabber* pGrabber = NULL;
hr = pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);
if (FAILED(hr))
{
TRACE("ERROR: could not get Sample Grabber interface\n");
pGrabberF->Release();
return hr;
}
```
4. 配置ISampleGrabber接口
在创建ISampleGrabber接口之后,我们需要通过配置ISampleGrabber接口的属性来捕获帧数据。主要有三个关键属性:媒体格式、回调函数和缓冲大小。
4.1 配置媒体格式
我们需要在接口对象上调用SetMediaType方法设置要捕获的音视频的媒体格式。如果我们对音视频的媒体格式不了解,我们可以使用GraphEdit或DirectShowSpy等工具获得媒体类型,然后将其转换为AM_MEDIA_TYPE结构体。
```C++
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video; // 指定媒体类型为视频
mt.subtype = MEDIASUBTYPE_RGB24; // 指定媒体子类型为RGB24
pGrabber->SetMediaType(&mt);
```
4.2 配置回调函数
指定回调函数是另一个重要的配置。我们需要在ISampleGrabber对象上调用SetCallback方法,指定我们实现的回调接口对象。在我们的应用程序中实现ISampleGrabberCB接口,并指向该实例。
```C++
ISampleGrabberCB* pSampleGrabberCB = new MySampleGrabberCB();
pGrabber->SetCallback(pSampleGrabberCB, 1);
```
4.3 配置缓冲大小
Programs that can change the size of filters should not use the IPersistStream interface, but instead should use a property page.
前面的调用仅仅是为了激活回调函数。我们可以调用GetConnectedMediaType方法来获取输入媒体类型,并使用其来决定缓冲区的大小。
```C++
AM_MEDIA_TYPE mt;
pInPin->ConnectionMediaType(&mt);
VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) mt.Format;
int buffer_size = (pVih->bmiHeader.biSizeImage * 2);
```
5. 实现回调函数
我们需要实现SampleCB或BufferCB函数。我们实现SampleCB函数时可以直接得到IMediaSample指针,而在实现BufferCB函数时需要手动从指针中读取数据。
```C++
STDMETHODIMP MySampleGrabberCB::SampleCB(double SampleTime, IMediaSample *pSample)
{
BYTE* pBuffer;
pSample->GetPointer(&pBuffer);
long lBytes = pSample->GetActualDataLength();
// 进行进一步的处理或者存储
...
return S_OK;
}
STDMETHODIMP MySampleGrabberCB::BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen)
{
// 获取缓冲区数据,并进行进一步的处理或存储
...
return S_OK;
}
```
6. 释放资源
最后,我们需要释放资源。我们需要在ISampleGrabber对象和回调接口对象上调用Release方法。
```C++
pGrabber->Release();
pSampleGrabberCB->Release();
```
总结
在本文中,我们学习了在应用程序中使用iSampleGrabberCB接口捕获音视频数据的方法。我们通过创建ISampleGrabber接口,并配置媒体格式、回调函数和缓冲大小来初始化该接口。最后,我们还需要实现回调函数和释放资源。使用iSampleGrabberCB接口可以轻松地获得音视频的帧数据,并对其进行二次处理或存储。