最近在做基于DirectXShow的视频预览及捕获静态图片的工作,使用VS2005,CLR C++开发
要完成的功能:
1 一个pictureBox中实现视频预览
2 通过button按钮事件从视频预览的video stream中捕获一张图片数据,并在另一个pictureBox中显示出来
3 捕获的同时视频预览窗口可以有暂时的停顿,捕获完毕要继续实现视频预览的功能
查阅了MSDN,也参考了DirectXShow的demo(Microsoft DirectX 9.0 SDK (Summer 2004)\Samples\C++\DirectShow目录下的Capture和Editing下的demo),采用了Sample Grabber Filter,使用SetBufferSamples( TRUE ) ;SetOneShot( FALSE )的模式.
问题是:
1 单独实现视频预览或单独实现从capture video stream中捕获一张图片都没问题
2 在预览视频的同时捕获图片出现问题,GetCurrentBuffer时出错
IMediaControl::Run之后使用GetCurrentBuffer获取图片大小出错,通过调试发现是因为Filter Graph的状态不对,MSDN中说调用GetCurrentBuffer方法的时候“Do not call this method while the filter graph is running.”。那我应该何时调用呢?在Run后调用Stop和Pause方法都不行,调用IMediaEvent::GetEvent方法测试,使用以下代码:
while (hr = pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0), SUCCEEDED(hr))
{
//add the evCode to a int array[]
}
发现一共返回了5个evCode,从array[0] --array[4]分别是:EC_PALETTE_CHANGED,EC_VIDEO_SIZE_CHANGED,EC_CLOCK_CHANGED,EC_PAUSED,EC_PAUSED
然后调用GetCurrentBuffer依然出错
难道除了Sleep就没有别的方法了么?
SetBufferSamples( TRUE )之后DirectShow到底做了什么?对Filter Graph有什么影响?如何知道何时调用GetCurrentBuffer?有没有详细的资料?
附代码:
HRESULT DSComment::CreatFilterGraph(){
HRESULT hr;
cli::pin_ptr<IGraphBuilder *> ppGraphManager = &pGraphManager;
cli::pin_ptr<ICaptureGraphBuilder2 *> ppCapture = &pCapture;
if(!ppGraphManager || !ppCapture){
return E_POINTER;
}
hr = CoCreateInstance (
CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER, //for add grephedit
IID_IGraphBuilder,
(void **) ppGraphManager
);
if (FAILED(hr)){
MessageBox::Show("Initial IFilterGraph2 failed!");
return E_NOINTERFACE;
}
// Create the capture graph builder
hr = CoCreateInstance (
CLSID_CaptureGraphBuilder2,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICaptureGraphBuilder2,
(void **) ppCapture
);
if (FAILED(hr)){
MessageBox::Show("Initial ICaptureGraphBuilder2 failed!");
return E_NOINTERFACE;
}
return S_OK;
}
HRESULT DSComment::CreatGrabberFilter(){
HRESULT hr;
cli::pin_ptr<IBaseFilter *> ppGrabberBaseFilter = &pGrabberBaseFilter;
hr = CoCreateInstance(
CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)ppGrabberBaseFilter
);
if (FAILED(hr))
{
MessageBox::Show("Couldn't create sample grabber filter base!");
return E_NOINTERFACE;
}
cli::pin_ptr<ISampleGrabber *> ppGrabber = &pGrabber;
pGrabberBaseFilter->QueryInterface(IID_ISampleGrabber, (void**)ppGrabber);
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = pGrabber->SetMediaType(&mt);
FreeMediaType(mt);
return hr;
}
HRESULT DSComment::CreatCaptureFilter(){
HRESULT hr;
ULONG cFetched;
const char* CAPTUREDEVNAME;
CAPTUREDEVNAME = "USB 视频设备";
cli::pin_ptr<IBaseFilter *> ppCaptureBaseFilter = &pCaptureBaseFilter;
// Create the system device enumerator
ICreateDevEnum *pDevEnum =NULL;
hr = CoCreateInstance (
CLSID_SystemDeviceEnum,
NULL,
CLSCTX_INPROC,
IID_ICreateDevEnum,
(void **) &pDevEnum
);
if (FAILED(hr)){
MessageBox::Show("Couldn't create system enumerator!");
return E_NOINTERFACE;
}
// Create an enumerator for the video capture devices
IEnumMoniker *pClassEnum = NULL;
hr = pDevEnum->CreateClassEnumerator(
CLSID_VideoInputDeviceCategory,
&pClassEnum,
0
);
if (FAILED(hr)){
MessageBox::Show("Couldn't create class enumerator!");
return E_NOINTERFACE;
}
// If there are no enumerators for the requested type, then
// CreateClassEnumerator will succeed, but pClassEnum will be NULL.
if (pClassEnum == NULL){
MessageBox::Show("No video capture device was detected.\r\n\r\n \