用摄像头预览过程如下:
ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder
// Initialize pBuild (not shown).
IBaseFilter *pCap; // Video capture filter.
/* Initialize pCap and add it to the filter graph (not shown). */
hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
pCap, NULL, NULL);
其中pBuild 初始化如下:
HRESULT InitCaptureGraphBuilder(
IGraphBuilder **ppGraph, // Receives the pointer.
ICaptureGraphBuilder2 **ppBuild // Receives the pointer.
)
{
if (!ppGraph || !ppBuild)
{
return E_POINTER;
}
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuild = NULL;
// Create the Capture Graph Builder.
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild );
if (SUCCEEDED(hr))
{
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
// Initialize the Capture Graph Builder.
pBuild->SetFiltergraph(pGraph);
// Return both interface pointers to the caller.
*ppBuild = pBuild;
*ppGraph = pGraph; // The caller must release both interfaces.
return S_OK;
}
else
{
pBuild->Release();
}
}
return hr; // Failed
}
pCap初始化,通过实例化一个capture filter,然后加入到graph链路。
枚举视频捕获设备如下:
ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;
// Create the System Device Enumerator.
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
reinterpret_cast<void**>(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the video capture category.
hr = pDevEnum->CreateClassEnumerator(
CLSID_VideoInputDeviceCategory,
&pEnum, 0);
}
显示设备信息如下:
HWND hList; // Handle to the list box.
IMoniker *pMoniker = NULL;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
{
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void**)(&pPropBag));
if (FAILED(hr))
{
pMoniker->Release();
continue; // Skip this one, maybe the next one will work.
}
// Find the description or friendly name.
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"Description", &varName, 0);
if (FAILED(hr))
{
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
}
if (SUCCEEDED(hr))
{
// Add it to the application's list box.
USES_CONVERSION;
(long)SendMessage(hList, LB_ADDSTRING, 0,
(LPARAM)OLE2T(varName.bstrVal));
VariantClear(&varName);
}
pPropBag->Release();
pMoniker->Release();
}
加入到链路:
IBaseFilter *pCap = NULL;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{
hr = m_pGraph->AddFilter(pCap, L"Capture Filter");
}
以上过程来自directshow帮助文档,整理后代码如下:
HRESULT InitCaptureGraphBuilder(
IGraphBuilder **ppGraph, // Receives the pointer.
ICaptureGraphBuilder2 **ppBuild // Receives the pointer.
)
{
if (!ppGraph || !ppBuild)
{
return E_POINTER;
}
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuild = NULL;
// Create the Capture Graph Builder.
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild );
if (SUCCEEDED(hr))
{
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
// Initialize the Capture Graph Builder.
pBuild->SetFiltergraph(pGraph);
// Return both interface pointers to the caller.
*ppBuild = pBuild;
*ppGraph = pGraph; // The caller must release both interfaces.
return S_OK;
}
else
{
pBuild->Release();
}
}
return hr; // Failed
}
HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
ICreateDevEnum *pDevEnum = NULL;
// Create the System Device Enumerator.
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
reinterpret_cast<void**>(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the video capture category.
hr = pDevEnum->CreateClassEnumerator(
CLSID_VideoInputDeviceCategory,
ppEnum, 0);
}
return hr;
}
void DisplayDeviceInformation(IEnumMoniker *pEnum, IMoniker** pMoniker)
{
HWND hList; // Handle to the list box.
while (pEnum->Next(1, pMoniker, NULL) == S_OK)
{
IPropertyBag *pPropBag;
HRESULT hr = (*pMoniker)->BindToStorage(0, 0, IID_IPropertyBag,
(void**)(&pPropBag));
if (FAILED(hr))
{
(*pMoniker)->Release();
continue; // Skip this one, maybe the next one will work.
}
// Find the description or friendly name.
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"Description", &varName, 0);
if (FAILED(hr))
{
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
}
if (SUCCEEDED(hr))
{
// Add it to the application's list box.
USES_CONVERSION;
/*(long)SendMessage(hList, LB_ADDSTRING, 0,
(LPARAM)OLE2T(varName.bstrVal));*/
VariantClear(&varName);
}
pPropBag->Release();
(*pMoniker)->Release();
}
}
调用代码:
ICaptureGraphBuilder2 *pBuild;
IGraphBuilder *ppGraph;
IMoniker* pMoniker;
IMediaControl *pControl;
IMediaEvent *pEvent;
InitCaptureGraphBuilder(&ppGraph,&pBuild);
hr = ppGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = ppGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
IBaseFilter *pCap; // Video capture filter.
IEnumMoniker *pEnum;
hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
DisplayDeviceInformation(pEnum, &pMoniker);
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{
hr = ppGraph->AddFilter(pCap, L"Capture Filter");
}
hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL);
hr = pControl->Run();
运行获得filter的连接情况:
接下就是把捕获的视频进行保存了
IBaseFilter *pMux;
hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi,L"D:\\Example.avi",&pMux,NULL);
hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,pCap,NULL,pMux);
程序调试了很久,刚开始链路是正确的,但是没办法播放,原因是存放地址放在了C盘,可能是win7 系统权限问题,修改保存路径到D盘就可以了。
如果需要对文件先进行编码,然后保存,代码如下:
Specify the encoder filter as the fourth parameter to RenderStream, shown in bold in the following example:
IBaseFilter *pEncoder;
/* Create the encoder filter (not shown). */
// Add it to the filter graph.
pGraph->AddFilter(pEncoder, L"Encoder);
/* Call SetOutputFileName as shown previously. */
// Render the stream.
hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
pCap, pEncoder, pMux);
pEncoder->Release();