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解析推流了。