正文

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 的指针,然后调用pin的put_Mode方法。 根据不同的摄像头,你可能静态pin连接前要render 该pin。 捕捉静态图片常用的filter是Sample 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; } };

阅读(16793) | 评论(0)


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

评论

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