原因:由于目前pc平台采集DirectShow老旧和复杂,故了解MediaFoundation简单调用。
概述:利用MediaFoundation实现视频采集,利用同步方式实现视频数据的读取。
MediaFoundation介绍:
MediaFoundation是DirectShow的替代,vist及以上才能支持,也就是说xp不支持,且不同的系统某些功能支持情况也不同,提供了两种编码模型,第一种是Media Session为主的Media pipeline模型,复杂。
第二种就是通过SourceReader,sinkWirter等模块开发,简单。
SDK Version | Libraries |
vista | evr.lib mf.lib mfplat.lib |
server2008 | |
win7 | 如果目标是server2008,链接库如下: evr_vista.lib,mf_vista.lib,mfplat_vist.lib 如果目标是win7或以上,链接库如下: evr.lib,mf.lib,mfplat.lib |
主要流程如下:
1:引入头文件和静态库
#include
#include
#include
#include
#pragma comment(lib,"mfplat.lib")
#pragma comment(lib,"mf.lib")
#pragma comment(lib,"Mfreadwrite.lib")
#pragma comment(lib,"mfuuid.lib")
#pragma comment(lib,"evr.lib")
初始化MF
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
hr = MFStartup(MF_VERSION);
枚举设备创建采集源,通过该方法目前发现不能找到本机的虚拟设备,只能找到对应的usb摄像头,如有知道望告知。
IMFMediaSource *pSource = nullptr;
IMFAttributes *pAttributes = nullptr;
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
MFEnumDeviceSources(pAttributes, &ppDevices, &count);
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(&pSource));
2:创建Source Reader用于数据读取
IMFSourceReader *pSourceReader = nullptr;
MFCreateSourceReaderFromMediaSource(*ppSource, nullptr/*pAttributes*/, &pSourceReader);
3:设置Source Reader媒体数据类型,此时如果媒体类型不支持则设置也会成功,但是读取数据时会失败,所以需要知道源设备支持的类型。
IMFMediaType *mediatype = nullptr;
hr = MFCreateMediaType(&mediatype);
mediatype->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
mediatype->SetGUID(MF_MT_SUBTYPE, WMMEDIASUBTYPE_YUY2); //设置支持的类型 否则读取失败
hr = MFSetAttributeSize(mediatype, MF_MT_FRAME_SIZE, 640, 480);
hr = pSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, nullptr, mediatype);
4:获取源设备支持类型,
IMFPresentationDescriptor *pDescriptor;
IMFStreamDescriptor *pStreamDes;
IMFMediaTypeHandler *pMediaHand;
IMFMediaType *pMediaType;
hr = pSource->CreatePresentationDescriptor(&pDescriptor);
hr = pDescriptor->GetStreamDescriptorByIndex(0, &bSelect, &pStreamDes);
hr = pStreamDes->GetMediaTypeHandler(&pMediaHand);
pMediaHand->GetMediaTypeCount(&dcount);
for(int i=0;iGetMediaTypeByIndex(i,&pMediaType);
pMediaType->GetCount();
....
}
5:同步读取数据
hr = pSourceReader->ReadSample(MF_SOURCE_READER_ANY_STREAM,
0, &index, &flags, &llvideoTs, &sampe);
if (sampe)
{
BYTE *data = nullptr;
IMFMediaBuffer *buffer = nullptr;
DWORD dmax=0, dcurrent = 0;
sampe->GetBufferByIndex(0, &buffer);
buffer->Lock(&data, &dmax, &dcurrent);
buffer->Unlock();
buffer->Release();
}
总结:上面就是利用MF简单的视频数据采集。相对于DShow简单了很多,不需要创建Grap,Filter,也不需要Pin的连接。