当前位置:   article > 正文

浅谈视频采集方案_mfplay 帧

mfplay 帧

现在手头上有一个项目就是需要优化采集方案。

我们这边之前使用的是作者Shiqi Yu写的开源代码,底层是基于DShow做的封装。但使用后发现采集到的视频流在进行回显时有点模糊,特别是文字部分。

现在通过万能的网络找到了三种替换方案:WebRTC 接、MediaFoundation、VideoInput。

1、WebRTC:现被Google整编,但由于需要翻墙才能下载和更新,所以没有使用。

2、MediaFoundation:微软基于DShow上做的优化框架,回显也明显清晰流畅了许多,但是继承了微软的封装特性,所以想嵌入自己的逻辑,相对于比较麻烦,所以放弃。

获取视频采集设备。

  1. HRESULT hr = S_OK;
  2. IMFAttributes *pAttributes;
  3. if (SUCCEEDED(hr))
  4. {
  5. hr = MFStartup(MF_VERSION); //这是必须的,不然无法绑定回调资源
  6. }
  7. if (SUCCEEDED(hr))
  8. {
  9. hr = MFCreateAttributes(&pAttributes, 1);
  10. }
  11. if (SUCCEEDED(hr))
  12. {
  13. hr = m_pAttributes->SetGUID(
  14. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
  15. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
  16. );
  17. }
  18. if (SUCCEEDED(hr))
  19. {
  20. hr = MFEnumDeviceSources(m_pAttributes, &m_param.ppDevices, &m_param.count);
  21. }
  22. SafeRelease(&pAttributes);

打开一个采集设备

  1. HRESULT hr = S_OK;
  2. IMFMediaSource *pSource = NULL;
  3. EnterCriticalSection(&m_critsec);
  4. IMFActivate* pActivate = m_param.ppDevices[nCamID];
  5. pActivate->AddRef();
  6. // Create the media source for the device.
  7. if (SUCCEEDED(hr))
  8. {
  9. hr = pActivate->ActivateObject(__uuidof(IMFMediaSource),
  10. (void**)&pSource
  11. );
  12. }
  13. // Get the symbolic link. This is needed to handle device-
  14. // loss notifications. (See CheckDeviceLost.)
  15. if (SUCCEEDED(hr))
  16. {
  17. hr = pActivate->GetAllocatedString(
  18. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
  19. &m_pwszSymbolicLink,
  20. &m_cchSymbolicLink
  21. );
  22. }
  23. WCHAR *szFriendlyName = NULL;
  24. if (SUCCEEDED(hr))
  25. {
  26. hr = pActivate->GetAllocatedString(
  27. MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
  28. &szFriendlyName,
  29. NULL
  30. );
  31. }
  32. UINT32 unMaxSize = 0;
  33. if (SUCCEEDED(hr))
  34. {
  35. hr = pActivate->GetUINT32(
  36. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_MAX_BUFFERS,
  37. &unMaxSize
  38. );
  39. }
  40. // When the method completes, MFPlay will call OnMediaPlayerEvent
  41. // with the MFP_EVENT_TYPE_MEDIAITEM_CREATED event.
  42. if (SUCCEEDED(hr))
  43. {
  44. hr = CreateSourceReaderAsync(pSource);
  45. }
  46. if (SUCCEEDED(hr))
  47. {
  48. m_pSource = pSource;
  49. m_pSource->AddRef();
  50. }
  51. if (FAILED(hr))
  52. {
  53. CloseCamera();
  54. }
  55. else
  56. {
  57. m_ob = ob;
  58. Start();
  59. }
  60. SafeRelease(&pSource);
  61. SafeRelease(&pActivate);
  62. LeaveCriticalSection(&m_critsec);

视频采集器绑定视频资源与回调
  1. HRESULT hr = S_OK;
  2. IMFAttributes *pAttributes = NULL;
  3. IMFMediaType * nativeType = NULL;
  4. hr = MFCreateAttributes(&pAttributes, 2);
  5. if (SUCCEEDED(hr))
  6. {
  7. hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this);
  8. }
  9. if (SUCCEEDED(hr))
  10. {
  11. hr = MFCreateSourceReaderFromMediaSource(pSource,pAttributes,&m_pSourceReader);
  12. }
  13. if (SUCCEEDED(hr))
  14. {
  15. hr = m_pSourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,NULL,nativeType);
  16. }
  17. SafeRelease(&nativeType);
  18. SafeRelease(&pAttributes);

视频流读取

  1. if (FAILED(hrStatus))
  2. {
  3. hr = hrStatus;
  4. LeaveCriticalSection(&m_critsec);
  5. return hr;
  6. }
  7. if(pSample )
  8. {
  9. DWORD maxLength,currentLength;
  10. BYTE* pBuffer = NULL;
  11. BYTE * pBitmapData = NULL;
  12. IMFMediaBuffer* pMBuffer = NULL;
  13. hr = pSample->GetBufferByIndex(0, &pMBuffer);
  14. //hr = pSample->ConvertToContiguousBuffer(&pMBuffer);
  15. if(SUCCEEDED(hr))
  16. {
  17. hr = pMBuffer->Lock(&pBuffer,&maxLength,¤tLength);
  18. }
  19. if(SUCCEEDED(hr))
  20. {
  21. hr = pMBuffer->Unlock();
  22. if(currentLength > 0)
  23. m_ob->onRGB((const char*)pBuffer,currentLength);
  24. SafeRelease(&pMBuffer);
  25. }
  26. }

3、VideoInput 被OpenCV收入的一个非常实用的开源视频采集库,现在我就使用的这个库。

打开一个采集设备

  1. if(pCamara)
  2. {
  3. delete pCamara;
  4. pCamara = NULL;
  5. }
  6. //videoInput::setComMultiThreaded(true); //如果项目中使用到不支持多线程的COM库,请不要执行此段代码
  7. pCamara = (void*)(new videoInput());
  8. ((videoInput*)pCamara)->setIdealFramerate(nCamID,25); //设置当前采集帧率默认为25帧,实际可能大于25帧。
  9. bool bRs = ((videoInput*)pCamara)->setupDevice(nCamID,nWidth,nHeight);
  10. if(bRs)
  11. {
  12. m_ob = ob;
  13. nDeviceId = nCamID;
  14. ((videoInput*)pCamara)->setUseCallback(true); //设置当前采集使用回调的方式获取数据
  15. hThread = (void*)CreateThread(NULL,0,OnCaptureFrame,this,0,0);
  16. m_bIsRun = true;
  17. }

通过推的方式采集RGB数据

  1. CCameraVI* pThis = (CCameraVI*)lpParam;
  2. while(pThis->isRun())
  3. {
  4. if(pThis->isFrameNew())
  5. {
  6. const char* pData = (const char*)pThis->GetFrame();
  7. pThis->getObserver()->onRGB(pData,pThis->GetWidth()*pThis->GetHeight()*3);
  8. }
  9. else
  10. {
  11. Sleep(1);
  12. }
  13. }
  14. return 0;

整个采集逻辑就是这么简单的两段代码实现。

获取设备数量

videoInput::listDevices();

获取设备名称

  1. videoInput::listDevices();
  2. strncpy(sName,videoInput::getDeviceName(nCamID),nBufferSize);

通过拉的方式采集RGB数据

  1. if (pCamara )
  2. {
  3. return ((videoInput*)pCamara)->getPixels(nDeviceId,false);
  4. }



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/1011591
推荐阅读
相关标签
  

闽ICP备14008679号