从静止图像固定捕获图像
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
某些相机可以生成独立于捕获流的静止图像,并且静态图像的质量通常比捕获流生成的图像质量更高。 相机可能具有充当硬件触发器的按钮,或者它可能支持软件触发。 支持静止图像的相机将公开静止图像引脚,这是固定类别PIN_CATEGORY_STILL。
从设备获取静止图像的建议方法是使用 Windows 映像采集 (WIA) API。 有关详细信息,请参阅平台 SDK 文档中的“Windows 映像获取”。 但是,也可以使用 DirectShow 来捕获图像。
若要触发静止引脚,请在图形运行时使用 IAMVideoControl::SetMode 方法,如下所示:
IAMVideoControl *pAMVidControl = NULL;
hr = pControl->Run(); // Run the graph.
if (FAILED(hr))
{
// Handle error.
}
hr = pCap->QueryInterface(IID_IAMVideoControl, (void**)&pAMVidControl);
if (SUCCEEDED(hr))
{
// Find the still pin.
IPin *pPin = NULL;
// pBuild is an ICaptureGraphBuilder2 pointer.
hr = pBuild->FindPin(
pCap, // Filter.
PINDIR_OUTPUT, // Look for an output pin.
&PIN_CATEGORY_STILL, // Pin category.
NULL, // Media type (don't care).
FALSE, // Pin must be unconnected.
0, // Get the 0'th pin.
&pPin // Receives a pointer to thepin.
);
if (SUCCEEDED(hr))
{
hr = pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger);
pPin->Release();
}
pAMVidControl->Release();
}
查询 IAMVideoControl 的捕获筛选器。 如果接口受支持,请通过调用 ICaptureGraphBuilder2::FindPin 方法获取指向固定固定的 IPin 接口的指针,如前面的示例所示。 然后使用 IPin 指针和 VideoControlFlag_Trigger 标志调用 IAMVideoControl::SetMode。
注意
根据相机的不同,可能需要先将捕获引脚呈现 (PIN_CATEGORY_CAPTURE) ,然后静止的图钉才会连接。
示例:使用示例抓取器筛选器
捕获图像的一种方法是使用 样本抓取器 筛选器。 示例抓取器使用应用程序定义的回调函数来处理图像。 有关示例抓取器筛选器的详细信息,请参阅 使用示例抓取器。
以下示例假定静止引脚提供未压缩的 RGB 图像。 首先,定义一个类,该类将实现 Sample Grabber 的回调接口 ISampleGrabberCB:
// Class to hold the callback function for the Sample Grabber filter.
class SampleGrabberCallback : public ISampleGrabberCB
{
// Implementation is described later.
}
// Global instance of the class.
SampleGrabberCallback g_StillCapCB;
稍后将介绍 类的实现。
接下来,将静止图钉连接到样本抓取器,并将样本抓取器连接到 Null 呈现器 筛选器。 Null 呈现器只是放弃它接收的媒体样本;实际工作将在回调中完成。 (Null 呈现器的唯一原因是将示例抓取器的输出引脚连接到某些内容。) 调用 CoCreateInstance 以创建 Sample Grabber 和 Null 呈现器筛选器,并调用 IFilterGraph::AddFilter 将这两个筛选器添加到图形:
// Add the Sample Grabber filter to the graph.
IBaseFilter *pSG_Filter;
hr = CoCreateInstance(
CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&pSG_Filter
);
hr = pGraph->AddFilter(pSG_Filter, L"SampleGrab");
// Add the Null Renderer filter to the graph.
IBaseFilter *pNull;
hr = CoCreateInstance(
CLSID_NullRenderer,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&pNull
);
hr = pGraph->AddFilter(pNull, L"NullRender");
可以使用 ICaptureGraphBuilder2::RenderStream 方法在一个方法调用中连接所有三个筛选器,从静止固定到 Sample Grabber,从 Sample Grabber 连接到 Null 呈现器:
hr = pBuild->RenderStream(
&PIN_CATEGORY_STILL, // Connect this pin ...
&MEDIATYPE_Video, // with this media type ...
pCap, // on this filter ...
pSG_Filter, // to the Sample Grabber ...
pNull); // ... and finally to the Null Renderer.
现在,使用 ISampleGrabber 接口配置 Sample Grabber,以便它缓冲样本:
// Configure the Sample Grabber.
ISampleGrabber *pSG = NULL;
hr = pSG_Filter->QueryInterface(IID_ISampleGrabber, (void**)&pSG);
if (SUCCEEDED(hr))
{
hr = pSG->SetOneShot(FALSE);
hr = pSG->SetBufferSamples(TRUE);
...
使用指向回调对象的指针设置回调接口:
hr = pSG->SetCallback(&g_StillCapCB, 0); // 0 = Use the SampleCB callback method.
获取仍固定用于与示例抓取器连接的媒体类型:
// Store the media type for later use.
AM_MEDIA_TYPE g_StillMediaType;
hr = pSG->GetConnectedMediaType(&g_StillMediaType);
pSG->Release();
此媒体类型将包含用于定义静止图像格式的 BITMAPINFOHEADER 结构。 在应用程序退出之前释放媒体类型:
// On exit, remember to release the media type.
FreeMediaType(g_StillMediaType);
下面是回调类的示例。 请注意, 类实现通过 ISampleGrabber 接口继承的 IUnknown,但它不保留引用计数。 这是安全的,因为应用程序在堆栈上创建对象,并且对象在整个筛选器图的生存期内一直处于范围内。
所有工作都发生在 BufferCB 方法中,每当获取新样本时,Sample Grabber 都会调用该方法。 在以下示例中, 方法将位图写入文件:
class SampleGrabberCallback : public ISampleGrabberCB
{
public:
// Fake referance counting.
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 2; }
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
{
if (NULL == ppvObject) return E_POINTER;
if (riid == __uuidof(IUnknown))
{
*ppvObject = static_cast<IUnknown*>(this);
return S_OK;
}
if (riid == __uuidof(ISampleGrabberCB))
{
*ppvObject = static_cast<ISampleGrabberCB*>(this);
return S_OK;
}
return E_NOTIMPL;
}
STDMETHODIMP SampleCB(double Time, IMediaSample *pSample)
{
return E_NOTIMPL;
}
STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen)
{
if ((g_StillMediaType.majortype != MEDIATYPE_Video) ||
(g_StillMediaType.formattype != FORMAT_VideoInfo) ||
(g_StillMediaType.cbFormat < sizeof(VIDEOINFOHEADER)) ||
(g_StillMediaType.pbFormat == NULL))
{
return VFW_E_INVALIDMEDIATYPE;
}
HANDLE hf = CreateFile("C:\\Example.bmp", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
if (hf == INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
long cbBitmapInfoSize = g_StillMediaType.cbFormat - SIZE_PREHEADER;
VIDEOINFOHEADER *pVideoHeader =
(VIDEOINFOHEADER*)g_StillMediaType.pbFormat;
BITMAPFILEHEADER bfh;
ZeroMemory(&bfh, sizeof(bfh));
bfh.bfType = 'MB'; // Little-endian for "BM".
bfh.bfSize = sizeof( bfh ) + BufferLen + cbBitmapInfoSize;
bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + cbBitmapInfoSize;
// Write the file header.
DWORD dwWritten = 0;
WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
WriteFile(hf, HEADER(pVideoHeader), cbBitmapInfoSize, &dwWritten, NULL);
WriteFile( hf, pBuffer, BufferLen, &dwWritten, NULL );
CloseHandle( hf );
return S_OK;
}
};
相关主题