正文

Direcshow中视频捕捉和参数设置报告-52006-04-19 11:00:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/ddtme/12742.html

分享到:

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;

}

};

阅读(7307) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册