MediaFoundation视频采集

原因:由于目前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的连接。

你可能感兴趣的:(DirecShow)