MFC实现ffmpeg流媒体数据推送与接收(1.获取设备)
本篇文章是基于ffmpeg的一个应用实例。做过流媒体的同学对于ffmepg比较了解,这里就不做介绍。直接进入实例分析:
我们这次实现ffmpeg.exe解析桌面,摄像头,麦克风设备推送rtmp流到nginx,通过代码从流媒体服务器接收数据流解析并播放。那么第一步我们就要获取我们设备。桌面我们可以使用gdigrab来获取,考虑一些原因摄像头麦克风使用的dshow。那么本节就用MFC代码获取dshow相关的设备名称。
CStringGetFirstCaptureDevices(const GUID devicesCLSID)
{
//enumerate all video capture devices
ICreateDevEnum*pCreateDevEnum = NULL;
HRESULThr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,(void**)&pCreateDevEnum);
IEnumMoniker*pEm = NULL;
hr= pCreateDevEnum->CreateClassEnumerator(devicesCLSID, &pEm, 0);
if(hr != NOERROR)
return0;
CStringstrDevicesName;
ULONGcFetched;
IMoniker*pM = NULL;
if(hr= pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
LPOLESTRstrPidvid = NULL;
hr= pM->GetDisplayName(0, 0, &strPidvid); //获取ID信息
if(SUCCEEDED(hr))
{
//这里获取了一下设备的ID
USES_CONVERSION;//OLE2T
CStringsPidvid = strPidvid;
stringstr = T2A(sPidvid);
stringresult;
staticconst regex re("(vid_[0-9a-f]{4}&pid_[0-9a-f]{4})",regex::icase);
smatchmatch;
if(regex_search(str, match, re) && match.size() > 1)
{
result= match.str(1);
}
else
{
result= string("");
}
CStringstrPid(result.c_str());
strPid.MakeUpper();//全部大写
IPropertyBag*pBag=0;
hr= pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANTvar;
var.vt= VT_BSTR;
hr= pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr== NOERROR)
{
//获取设备名称
chardevices_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1,devices_name, sizeof(devices_name) ,"",NULL);
strDevicesName= CString(devices_name);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
}
pM->Release();
}
pEm->Release();
pCreateDevEnum->Release();
returnstrDevicesName;
}
通过传递CLSID_VideoInputDeviceCategory获取第一个摄像头设备名,传递CLSID_AudioInputDeviceCategory获取第一个麦克风设备名。由于简单应用我们就只获取第一设备。使用时加上头文件Dshow.h,regex.h及strmiids.lib;quartz.lib;dmoguids.lib。至此我们获取到了我们需要的设备名称,接下来我们就可以通过ffmpeg.exe解析推流了。