Direcshow中视频捕捉和参数设置报告-5

7.      将设备从系统中移走时的事件通知(Device remove Notify

如果用户将一个graph正在使用的即插即用型的设备从系统中去掉,filter图表管理器就会发送一个EC_DEVICE_LOST事件通知,如果该设备又可以使用了,filter图表管理器就发送另外的一个EC_DEVICE_LOST通知,但是先前组建的捕捉filter graph图就没法用了,用户必须重新组建graph图。

当系统中有新的设备添加时,dshow是不会发送任何通知的,所以,应用程序如果想要知道系统中何时添加新的设备,应用程序可以监控WM_DEVICECHANGE消息。

8.      从静止图像pin中捕捉图片

有些照相机,摄像头除了可以捕获视频流以外还可以捕获单张的,静止的图片。通常,静止的图片的质量要比流的质量要高。摄像头一般都一个按钮来触发,或者是支持软件触发。支持输出静态图片的摄像头一般都要提供一个静态图片pin,这个pin的种类是PIN_CATEGORY_STILL

从设备中获取静态图片,我们一般推荐使用windows Image Acquisition (WIA) APIs。当然,你也可以用dshow来获取图片。

graph运行的时候利用IAMVideoControl::SetMode来触发静态的pin。代码如下

 pControl->Run(); // Run the graph.

 IAMVideoControl *pAMVidControl = NULL;

 hr = pCap->QueryInterface(IID_IAMVideoControl, (void**)&pAMVidControl);

 if (SUCCEEDED(hr))

 {

 // Find the still pin.

 IPin *pPin = 0;

 hr = pBuild->FindPin(pCap, PINDIR_OUTPUT, &PIN_CATEGORY_STILL, 0, FALSE, 0, &pPin);

 if (SUCCEEDED(hr))

 {

 hr = pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger);

 pPin->Release();

 }

 pAMVidControl->Release();

 }

首先向capture Filter 请求IAMVideoContol,如果支持该接口,就调用ICaptureGraphBuilder2::FindPin请求指向静止pin 的指针,然后调用pinput_Mode方法。

根据不同的摄像头,你可能静态pin连接前要render pin

捕捉静态图片常用的filterSample Grabber filterSample Grabber使用了一个用户定义的回调汗水来处理图片。关于这个filter的详细用法,参见Using the Sample Grabber.

下面的例子假设静态pin传递的是没有压缩的RGB图片。首先定义一个类,从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;

然后将捕捉filter的静态pin连接到Sample Grabber,将Sample Grabber连接到Null Renderer filterNull Renderer仅仅是将她接收到的sample丢弃掉。实际的工作都是在回调函数里进行,连接Null Renderer 仅仅是为了给Sample Grabber's 输出pin上连接点东西。具体见下面的代码

 // 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_NullRendere, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pNull);

hr = pGraph->AddFilter(pSG_Filter, L"NullRender");

然后通过RenderStreamstill pin sample grabber null Renderer连接起来

 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指针,来通过这个指针可以分配内存。

 // Configure the Sample Grabber.

 ISampleGrabber *pSG;

 hr = pSG_Filter->QueryInterface(IID_ISampleGrabber, (void**)&pSG);

 pSG->SetOneShot(FALSE);

 pSG->SetBufferSamples(TRUE);

设置你的回调对象

 pSG->SetCallback(&g_StillCapCB, 0); // 0 = Use the SampleCB callback   method

获取静态pinsample grabber之间连接所用的媒体类型

 // 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接口派生,但是它没有保持引用计数,因为应用程序在堆上创建这个对象,在整个graph的生存周期它都存在。

所有的工作都在BufferCB函数里完成,当有一个新的sample到来的时候,这个函数就会被sample Grabber调用到。在下面的例子里,bitmap被写入到一个文件中

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 "MB".

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;

}

};

posted on 2008-07-22 10:44  物质法则  阅读(1275)  评论(0编辑  收藏  举报