3.使用DShow进行摄像头预览并拍照
来源:互联网 发布:怎么备份游戏数据 编辑:程序博客网 时间:2024/05/15 08:13
上一篇讲了怎么采集摄像头图像并预览,本篇主要讲预览的同时怎么拍照。
拍照就需要抓取图像,这里要用到一个不太一样的Filter,叫SampleGrabber Filter,通过这个Filter可以获取到ISampleGrabber接口,通过这个接口就可以设置抓取什么样的视频。对于这个接口获取采集到的每一帧的信息,我们可以对其进行处理,可以拿来显示,也可以用来生成图片。下面来一步一步做做看。
首先,我新定义了一个结构,用来存采集设备支持的所有分辨率,ASCamResolutionInfoArray m_arrCamResolutionArr; 它的结构定义如下:
struct CamResolutionInfo{int nWidth;//分辨率宽int nHeight;//分辨率高int nResolutionIndex;//分辨率序号CamResolutionInfo(){nWidth = 640;nHeight = 480;nResolutionIndex = -1;};CamResolutionInfo(const CamResolutionInfo &other){*this = other;};CamResolutionInfo& operator = (const CamResolutionInfo& other){nWidth = other.nWidth;nHeight = other.nHeight;nResolutionIndex = other.nResolutionIndex;return *this;};};typedef CArray <CamResolutionInfo, CamResolutionInfo&> ASCamResolutionInfoArray;然后获取采集设备支持的所有分辨率,代码如下:
void CGetDeviceInfoDlg::GetVideoResolution(){if (m_pCapture){m_arrCamResolutionArr.RemoveAll();m_cbxResolutionCtrl.ResetContent();IAMStreamConfig *pConfig = NULL; //&MEDIATYPE_Video,如果包括其他媒体类型,第二个参数设置为0HRESULT hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoFilter, IID_IAMStreamConfig, (void **)&pConfig);int iCount = 0, iSize = 0;hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);// Check the size to make sure we pass in the correct structure.if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)){// Use the video capabilities structure.for (int iFormat = 0; iFormat < iCount; iFormat++){VIDEO_STREAM_CONFIG_CAPS scc;AM_MEDIA_TYPE *pmtConfig = NULL;hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);if (SUCCEEDED(hr)){//(pmtConfig->subtype == MEDIASUBTYPE_RGB24) &&if ((pmtConfig->majortype == MEDIATYPE_Video) &&(pmtConfig->formattype == FORMAT_VideoInfo) &&(pmtConfig->cbFormat >= sizeof (VIDEOINFOHEADER)) &&(pmtConfig->pbFormat != NULL)){VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;// pVih contains the detailed format information.LONG lWidth = pVih->bmiHeader.biWidth;LONG lHeight = pVih->bmiHeader.biHeight;BOOL bFind = FALSE;//是否已经存在这个分辨率,不存在就加入arrayfor (int n=0; n < m_arrCamResolutionArr.GetSize(); n++){CamResolutionInfo sInfo = m_arrCamResolutionArr.GetAt(n);if (sInfo.nWidth == lWidth && sInfo.nHeight == lHeight){bFind = TRUE;break;}}if (!bFind){CamResolutionInfo camInfo;camInfo.nResolutionIndex = iFormat;camInfo.nWidth = lWidth;camInfo.nHeight = lHeight;m_arrCamResolutionArr.Add(camInfo);CString strFormat = _T("");strFormat.Format(_T("%d * %d"), lWidth, lHeight);m_cbxResolutionCtrl.AddString(strFormat);}}// Delete the media type when you are done.FreeMediaType(pmtConfig);}}}if (m_cbxResolutionCtrl.GetCount() > 0){m_cbxResolutionCtrl.SetCurSel(0);}}}void CGetDeviceInfoDlg::FreeMediaType(AM_MEDIA_TYPE *pmt){if (pmt == NULL){return;} if (pmt->cbFormat != 0) { CoTaskMemFree((PVOID)pmt->pbFormat); // Strictly unnecessary but tidier pmt->cbFormat = 0; pmt->pbFormat = NULL; } if (pmt->pUnk != NULL) { pmt->pUnk->Release(); pmt->pUnk = NULL; }}获取到所有分辨率后,选择一个,其实就得到选择的分辨率序号,在后面的代码中对其进行设置。代码如下:
//设置视频分辨率、格式IAMStreamConfig *pConfig = NULL; m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoFilter, IID_IAMStreamConfig, (void **) &pConfig);AM_MEDIA_TYPE *pmt = NULL; VIDEO_STREAM_CONFIG_CAPS scc;pConfig->GetStreamCaps(nResolutionIndex, &pmt, (BYTE*)&scc); //nResolutionIndex就是选择的分辨率序号pConfig->SetFormat(pmt);
这些都做好后,就开始创建SampleGrabber Filter,代码如下:
//创建视频捕捉实例 HRESULT hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&m_pGrabberFilter); if (m_pGrabberFilter == NULL){MessageBox(_T("获取m_pGrabberFilter失败"), _T("提示"));return;}
//将视频捕捉过滤器加入图表hr = m_pGraphBuilder->AddFilter(m_pGrabberFilter, L"Grabber");if(S_OK != hr){MessageBox(_T("Fail to put sample grabber in graph"));return;}再获取ISampleGrabber接口,并设置要抓取的视频
m_pGrabberFilter->QueryInterface(IID_ISampleGrabber, (void **)&m_pGrabber);pmt->majortype = MEDIATYPE_Video;pmt->subtype = MEDIASUBTYPE_RGB24; //抓取24位位图HRESULT hr = m_pGrabber->SetMediaType(pmt);if(FAILED(hr)){AfxMessageBox(_T("Fail to set media type!"));return;}接下来一步非常重要,设置是否缓存,如果设置了缓存,则可以用接口获取到缓存数据,并生成图片,如果不设置缓存,则需要设置回调函数,在回调函数中获取到帧的数据,并生成图片,两种方法都可以,根据实际需要来选择。我这里就用缓存的方式,设置方法如下:
//是否缓存数据,缓存的话,可以给后面做其他处理,不缓存的话,图像处理就放在回调中
m_pGrabber->SetBufferSamples( TRUE );
如果用设置回调的方法,请调用m_pGrabber->SetCallback(...,...),第一个参数就是回调函数的名称,是一个结构的实例,这个结构里有两个虚函数:SampleCB和BufferCB,所以你需要写一个类继承这个结构,然后重载这两个函数,看两个函数的参数,就知道怎么处理 了。
接下来就是链接Filter,代码如下:
m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVideoFilter, m_pGrabberFilter, NULL);
后面就是设置预览窗口,然后拍照,拍照代码如下:
void CGetDeviceInfoDlg::OnBnClickedBtnTakepic(){//获取抓取buffer大小long nBufferSize = 0; HRESULT hr = m_pGrabber->GetCurrentBuffer(&nBufferSize, NULL); if(FAILED(hr)){AfxMessageBox(_T("Get BufferSize failed"));return;}//获取抓取的data数据BYTE *pBuffer = new BYTE[nBufferSize]; hr = m_pGrabber-> GetCurrentBuffer(&nBufferSize, (long*)pBuffer); if(FAILED(hr)){AfxMessageBox(_T("Get BufferData failed"));}AM_MEDIA_TYPE mt; hr = m_pGrabber->GetConnectedMediaType(&mt); VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat; int nWidth = vih->bmiHeader.biWidth; int nHeight = vih->bmiHeader.biHeight; FreeMediaType(&mt);//生成图片CTime cTime = CTime::GetCurrentTime();CString strTime = cTime.Format(_T("%Y%m%d_%H%M%S.bmp"));CString strFullPath = _T("");strFullPath.Format(_T("D:\\JYSoft\\temp\\%s"), strTime); //文件头 BITMAPFILEHEADER bfh; memset(&bfh, 0, sizeof(bfh)); bfh.bfType = 'MB'; bfh.bfSize = sizeof(bfh) + nBufferSize + sizeof(BITMAPINFOHEADER); bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER); //格式信息 BITMAPINFOHEADER bih; memset(&bih, 0, sizeof(bih)); bih.biSize = sizeof(bih); bih.biWidth = nWidth; bih.biHeight = nHeight; bih.biPlanes = 1; bih.biBitCount = 24;bih.biCompression = BI_RGB; //非压缩 CFile file;if(file.Open(strFullPath, CFile::modeWrite | CFile::modeCreate)) {//写入文件 file.Write((LPSTR)&bfh,sizeof(BITMAPFILEHEADER)); file.Write((LPSTR)&bih,sizeof(BITMAPINFOHEADER)); file.Write(pBuffer, nBufferSize); file.Close(); } //用完释放delete[] pBuffer;}
拍照生成bmp图片,最后的界面如下:
具体工程代码,请到这里下载:工程代码下载
如有什么问题,请多指教。
0 0
- 3.使用DShow进行摄像头预览并拍照
- 2.使用DShow进行摄像头预览
- html调用摄像头拍照,并生成预览
- html5实现摄像头拍照并使用java进行照片保存
- dshow在应用程序改摄像头拍照分辨率
- HTML 5调用摄像头并进行拍照
- 实现asp程序调用摄像头并控制摄像头进行拍照
- 使用摄像头进行拍照的步骤
- 使用摄像头进行拍照的步骤
- 使用手机的摄像头进行拍照
- 使用Java调用摄像头进行拍照源码
- flex 摄像头拍照预览 功能
- JavaSeript实现摄像头拍照预览
- 为什么摄像头会出现拍照时有预览图片并可以拍照,但是录像时却没有预览图片?
- 微信浏览器内兼容android iOS调取手机摄像头进行拍照、打水印、压缩、预览
- android Camera摄像头-Surface view 预览拍照 并将拍的照片插入到系统图库
- SliverLight使用摄像头拍照并上传到数据库
- C#使用摄像头拍照
- 使用SIMD技术提高C++程序性能
- js去选中
- 搭建OpenGL环境(32位操作系统+VS2010)
- Linux下查看系统版本号信息的方法
- 二叉树的层序遍历
- 3.使用DShow进行摄像头预览并拍照
- WPF开发进阶
- BZOJ 1121: [POI2008]激光发射器SZK 光路可逆,物理
- js 下拉框选中的值
- 用XMLHTTPRequest来进行ajax异步数据交交互
- js修改checkbox选中状态
- 如何验证group by的查询SQL中是否包含重复数据
- Leetcode 132 - Palindrome Partitioning II(dp)
- Snowflake算法