浅谈视频采集方案
2016-03-11 10:43
375 查看
现在手头上有一个项目就是需要优化采集方案。
我们这边之前使用的是作者Shiqi Yu写的开源代码,底层是基于DShow做的封装。但使用后发现采集到的视频流在进行回显时有点模糊,特别是文字部分。
现在通过万能的网络找到了三种替换方案:WebRTC 接、MediaFoundation、VideoInput。
1、WebRTC:现被Google整编,但由于需要翻墙才能下载和更新,所以没有使用。
2、MediaFoundation:微软基于DShow上做的优化框架,回显也明显清晰流畅了许多,但是继承了微软的封装特性,所以想嵌入自己的逻辑,相对于比较麻烦,所以放弃。
获取视频采集设备。
打开一个采集设备
视频采集器绑定视频资源与回调
视频流读取
3、VideoInput 被OpenCV收入的一个非常实用的开源视频采集库,现在我就使用的这个库。
打开一个采集设备
通过推的方式采集RGB数据
整个采集逻辑就是这么简单的两段代码实现。
获取设备数量
获取设备名称
通过拉的方式采集RGB数据
我们这边之前使用的是作者Shiqi Yu写的开源代码,底层是基于DShow做的封装。但使用后发现采集到的视频流在进行回显时有点模糊,特别是文字部分。
现在通过万能的网络找到了三种替换方案:WebRTC 接、MediaFoundation、VideoInput。
1、WebRTC:现被Google整编,但由于需要翻墙才能下载和更新,所以没有使用。
2、MediaFoundation:微软基于DShow上做的优化框架,回显也明显清晰流畅了许多,但是继承了微软的封装特性,所以想嵌入自己的逻辑,相对于比较麻烦,所以放弃。
获取视频采集设备。
HRESULT hr = S_OK; IMFAttributes *pAttributes; if (SUCCEEDED(hr)) { hr = MFStartup(MF_VERSION); //这是必须的,不然无法绑定回调资源 } if (SUCCEEDED(hr)) { hr = MFCreateAttributes(&pAttributes, 1); } if (SUCCEEDED(hr)) { hr = m_pAttributes->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID ); } if (SUCCEEDED(hr)) { hr = MFEnumDeviceSources(m_pAttributes, &m_param.ppDevices, &m_param.count); } SafeRelease(&pAttributes);
打开一个采集设备
HRESULT hr = S_OK; IMFMediaSource *pSource = NULL; EnterCriticalSection(&m_critsec); IMFActivate* pActivate = m_param.ppDevices[nCamID]; pActivate->AddRef(); // Create the media source for the device. if (SUCCEEDED(hr)) { hr = pActivate->ActivateObject(__uuidof(IMFMediaSource), (void**)&pSource ); } // Get the symbolic link. This is needed to handle device- // loss notifications. (See CheckDeviceLost.) if (SUCCEEDED(hr)) { hr = pActivate->GetAllocatedString( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &m_pwszSymbolicLink, &m_cchSymbolicLink ); } WCHAR *szFriendlyName = NULL; if (SUCCEEDED(hr)) { hr = pActivate->GetAllocatedString( MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, NULL ); } UINT32 unMaxSize = 0; if (SUCCEEDED(hr)) { hr = pActivate->GetUINT32( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_MAX_BUFFERS, &unMaxSize ); } // When the method completes, MFPlay will call OnMediaPlayerEvent // with the MFP_EVENT_TYPE_MEDIAITEM_CREATED event. if (SUCCEEDED(hr)) { hr = CreateSourceReaderAsync(pSource); } if (SUCCEEDED(hr)) { m_pSource = pSource; m_pSource->AddRef(); } if (FAILED(hr)) { CloseCamera(); } else { m_ob = ob; Start(); } SafeRelease(&pSource); SafeRelease(&pActivate); LeaveCriticalSection(&m_critsec);
视频采集器绑定视频资源与回调
HRESULT hr = S_OK; IMFAttributes *pAttributes = NULL; IMFMediaType * nativeType = NULL; hr = MFCreateAttributes(&pAttributes, 2); if (SUCCEEDED(hr)) { hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this); } if (SUCCEEDED(hr)) { hr = MFCreateSourceReaderFromMediaSource(pSource,pAttributes,&m_pSourceReader); } if (SUCCEEDED(hr)) { hr = m_pSourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,NULL,nativeType); } SafeRelease(&nativeType); SafeRelease(&pAttributes);
视频流读取
if (FAILED(hrStatus)) { hr = hrStatus; LeaveCriticalSection(&m_critsec); return hr; } if(pSample ) { DWORD maxLength,currentLength; BYTE* pBuffer = NULL; BYTE * pBitmapData = NULL; IMFMediaBuffer* pMBuffer = NULL; hr = pSample->GetBufferByIndex(0, &pMBuffer); //hr = pSample->ConvertToContiguousBuffer(&pMBuffer); if(SUCCEEDED(hr)) { hr = pMBuffer->Lock(&pBuffer,&maxLength,¤tLength); } if(SUCCEEDED(hr)) { hr = pMBuffer->Unlock(); if(currentLength > 0) m_ob->onRGB((const char*)pBuffer,currentLength); SafeRelease(&pMBuffer); } }
3、VideoInput 被OpenCV收入的一个非常实用的开源视频采集库,现在我就使用的这个库。
打开一个采集设备
if(pCamara) { delete pCamara; pCamara = NULL; } //videoInput::setComMultiThreaded(true); //如果项目中使用到不支持多线程的COM库,请不要执行此段代码 pCamara = (void*)(new videoInput()); ((videoInput*)pCamara)->setIdealFramerate(nCamID,25); //设置当前采集帧率默认为25帧,实际可能大于25帧。 bool bRs = ((videoInput*)pCamara)->setupDevice(nCamID,nWidth,nHeight); if(bRs) { m_ob = ob; nDeviceId = nCamID; ((videoInput*)pCamara)->setUseCallback(true); //设置当前采集使用回调的方式获取数据 hThread = (void*)CreateThread(NULL,0,OnCaptureFrame,this,0,0); m_bIsRun = true; }
通过推的方式采集RGB数据
CCameraVI* pThis = (CCameraVI*)lpParam; while(pThis->isRun()) { if(pThis->isFrameNew()) { const char* pData = (const char*)pThis->GetFrame(); pThis->getObserver()->onRGB(pData,pThis->GetWidth()*pThis->GetHeight()*3); } else { Sleep(1); } } return 0;
整个采集逻辑就是这么简单的两段代码实现。
获取设备数量
videoInput::listDevices();
获取设备名称
videoInput::listDevices(); strncpy(sName,videoInput::getDeviceName(nCamID),nBufferSize);
通过拉的方式采集RGB数据
if (pCamara ) { return ((videoInput*)pCamara)->getPixels(nDeviceId,false); }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性