当前位置: 代码迷 >> 驱动开发 >> DirectXShow开发-实现视频预览和捕获静态图片功能出现的有关问题
  详细解决方案

DirectXShow开发-实现视频预览和捕获静态图片功能出现的有关问题

热度:57   发布时间:2016-04-28 10:12:29.0
DirectXShow开发-实现视频预览和捕获静态图片功能出现的问题
最近在做基于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, &param1, &param2, 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   \
  相关解决方案