从静止图像pin中捕捉图片

.Net技术 码拜 11年前 (2013-12-01) 3164次浏览 0个评论

有些照相机,摄像头除了可以捕获视频流以外还可以捕获单张的,静止的图片。通常,静止的图片的质量要比流的质量要高。摄像头一般都一个按钮来触发,或者是支持软件触发。支持输出静态图片的摄像头一般都要提供一个静态图片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 的指针,然后调用pin的put_Mode方法。

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

捕捉静态图片常用的filterSample Grabber filter,Sample 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 filter。Null 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”);

然后通过RenderStream将still 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

获取静态pin和sample 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;

}

};


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明从静止图像pin中捕捉图片
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!