1 Star 1 Fork 1

柏松/DShowCaptureToLocal

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
GetDeviceInfoDlg.cpp 26.75 KB
一键复制 编辑 原始数据 按行查看 历史
柏松 提交于 2017-08-31 15:25 . 加入回调函数中控制帧率
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
// GetDeviceInfoDlg.cpp : implementation file
//
#include "stdafx.h"
#include "GetDeviceInfo.h"
#include "GetDeviceInfoDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CGetDeviceInfoDlg dialog
CGetDeviceInfoDlg::CGetDeviceInfoDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CGetDeviceInfoDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_asVideoDeviceInfo.RemoveAll();
m_asAudioDeviceInfo.RemoveAll();
m_asCompressDeviceInfo.RemoveAll();
m_asAudioCompressorInfo.RemoveAll();
m_arrCamResolutionArr.RemoveAll();
m_pGraphBuilder = NULL;
m_pCapture = NULL;
m_pMediaControl = NULL;
m_pVW = NULL;
m_pVideoFilter = NULL;
m_pGrabberFilter = NULL;
m_pAudioFilter = NULL;
m_hShowWnd = NULL;
m_bIsVideoOpen = FALSE;
m_bRendered = FALSE;
m_pGrabber = NULL;
}
void CGetDeviceInfoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_CBO_DSHOW_DEVICE, m_cbxCtrl);
DDX_Control(pDX, IDC_CBO_AUDIO_DEVICE, m_cbxAudioCtrl);
DDX_Control(pDX, IDC_CBO_COMPRESS_DEVICE, m_cbxCompressCtrl);
DDX_Control(pDX, IDC_CBO_AUDIO_COMPRESSOR, m_cbxAudioCompressor);
DDX_Control(pDX, IDC_CBO_VIDEO_RESOLUTION, m_cbxResolutionCtrl);
}
BEGIN_MESSAGE_MAP(CGetDeviceInfoDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_GETDEVICE, &CGetDeviceInfoDlg::OnBnClickedBtnGetdevice)
ON_BN_CLICKED(IDC_BTN_INIT, &CGetDeviceInfoDlg::OnBnClickedBtnInit)
ON_BN_CLICKED(IDC_BTN_PREVIEW, &CGetDeviceInfoDlg::OnBnClickedBtnPreview)
ON_BN_CLICKED(IDC_BTN_STOP, &CGetDeviceInfoDlg::OnBnClickedBtnStop)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_BTN_TAKEPIC, &CGetDeviceInfoDlg::OnBnClickedBtnTakepic)
END_MESSAGE_MAP()
// CGetDeviceInfoDlg message handlers
BOOL CGetDeviceInfoDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CGetDeviceInfoDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CGetDeviceInfoDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CGetDeviceInfoDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
//枚举视频采集设备
BOOL CGetDeviceInfoDlg::ListVideoCaptureDevices()
{
int count = 0;
ImgDeviceInfo sDevice;
// enumerate all video capture devices
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
IEnumMoniker *pEm = NULL;//Moniker--绰号
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);//CLSID_VideoInputDeviceCategory
if (hr != NOERROR)
return 0;
ULONG cFetched;
IMoniker *pM = NULL;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
sDevice.nDeviceIndex = count;
LPOLESTR strPidvid = NULL;
hr = pM->GetDisplayName(0, 0, &strPidvid); //获取ID信息
if(SUCCEEDED(hr))
{
//这里获取了一下设备的ID
USES_CONVERSION; //OLE2T
CString sPidvid = strPidvid;
string str = T2A(sPidvid);
string result;
static const regex re("(vid_[0-9a-f]{4}&pid_[0-9a-f]{4})",regex::icase);
smatch match;
if (regex_search(str, match, re) && match.size() > 1)
{
result = match.str(1);
}
else
{
result = string("");
}
CString strPid(result.c_str());
strPid.MakeUpper(); //全部大写
sDevice.strDevicePidVid = strPid;
IPropertyBag *pBag=0;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr == NOERROR)
{
//获取设备名称
char camera_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1, camera_name, sizeof(camera_name) ,"",NULL);
CString str(camera_name);
sDevice.strDeviceName = str;
m_asVideoDeviceInfo.Add(sDevice);
m_cbxCtrl.AddString(str);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
}
pM->Release();
count++;
}
if (m_cbxCtrl.GetCount() > 0)
{
m_cbxCtrl.SetCurSel(0);
}
pEm->Release();
pCreateDevEnum->Release();
return 1;
}
//枚举音频采集设备
BOOL CGetDeviceInfoDlg::ListAudioCaptureDevices()
{
int count = 0;
ImgDeviceInfo sDevice;
// enumerate all Audio capture devices
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
IEnumMoniker *pEm = NULL;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEm, 0);//CLSID_AudioInputDeviceCategory
if (hr != NOERROR)
return 0;
ULONG cFetched;
IMoniker *pM = NULL;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
sDevice.nDeviceIndex = count;
LPOLESTR strPidvid = NULL;
hr = pM->GetDisplayName(0, 0, &strPidvid); //获取ID信息
if(SUCCEEDED(hr))
{
USES_CONVERSION; //OLE2T
CString sPidvid = strPidvid;
string str = T2A(sPidvid);
string result;
static const regex re("(vid_[0-9a-f]{4}&pid_[0-9a-f]{4})",regex::icase);
smatch match;
if (regex_search(str, match, re) && match.size() > 1)
{
result = match.str(1);
}
else
{
result = string("");
}
CString strPid(result.c_str());
strPid.MakeUpper(); //全部大写
sDevice.strDevicePidVid = strPid;
IPropertyBag *pBag=0;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr == NOERROR)
{
//获取设备名称
char camera_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1, camera_name, sizeof(camera_name) ,"",NULL);
CString str(camera_name);
sDevice.strDeviceName = str;
m_asAudioDeviceInfo.Add(sDevice);
m_cbxAudioCtrl.AddString(str);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
}
pM->Release();
count++;
}
if (m_cbxAudioCtrl.GetCount() > 0)
{
m_cbxAudioCtrl.SetCurSel(0);
}
pEm->Release();
pCreateDevEnum->Release();
return 1;
}
BOOL CGetDeviceInfoDlg::ListVideoCompressDevices()
{
int count = 0;
ImgDeviceInfo sDevice;
// enumerate all Audio capture devices
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
IEnumMoniker *pEm = NULL;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEm, 0);//视频压缩编码
if (hr != NOERROR)
return 0;
ULONG cFetched;
IMoniker *pM = NULL;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
sDevice.nDeviceIndex = count;
IPropertyBag *pBag=0;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr == NOERROR)
{
//获取设备名称
char camera_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1, camera_name, sizeof(camera_name) ,"",NULL);
CString str(camera_name);
sDevice.strDeviceName = str;
m_asCompressDeviceInfo.Add(sDevice);
m_cbxCompressCtrl.AddString(str);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
pM->Release();
count++;
}
if (m_cbxCompressCtrl.GetCount() > 0)
{
m_cbxCompressCtrl.SetCurSel(0);
}
pEm->Release();
pCreateDevEnum->Release();
return 1;
}
BOOL CGetDeviceInfoDlg::ListAudioCompressDevices()
{
int count = 0;
ImgDeviceInfo sDevice;
// enumerate all Audio compressor
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
IEnumMoniker *pEm = NULL;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioCompressorCategory, &pEm, 0);//音频压缩编码
if (hr != NOERROR)
return 0;
ULONG cFetched;
IMoniker *pM = NULL;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
sDevice.nDeviceIndex = count;
IPropertyBag *pBag=0;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr == NOERROR)
{
//获取设备名称
char camera_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1, camera_name, sizeof(camera_name) ,"",NULL);
CString str(camera_name);
sDevice.strDeviceName = str;
m_asAudioCompressorInfo.Add(sDevice);
m_cbxAudioCompressor.AddString(str);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
pM->Release();
count++;
}
if (m_cbxAudioCompressor.GetCount() > 0)
{
m_cbxAudioCompressor.SetCurSel(0);
}
pEm->Release();
pCreateDevEnum->Release();
return 1;
}
void CGetDeviceInfoDlg::OnBnClickedBtnGetdevice()
{
m_cbxCtrl.ResetContent();
m_cbxAudioCtrl.ResetContent();
m_cbxCompressCtrl.ResetContent();
m_cbxAudioCompressor.ResetContent();
m_asVideoDeviceInfo.RemoveAll();
m_asAudioDeviceInfo.RemoveAll();
m_asCompressDeviceInfo.RemoveAll();
m_asAudioCompressorInfo.RemoveAll();
ListVideoCaptureDevices();
ListAudioCaptureDevices();
ListVideoCompressDevices();
ListAudioCompressDevices();
}
//创建视频采集过滤器图表
HRESULT CGetDeviceInfoDlg::InitCaptureGraphBuilder(IGraphBuilder **ppGraph, ICaptureGraphBuilder2 **ppBuild)
{
if (!ppGraph || !ppBuild)
{
return E_POINTER;
}
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuild = NULL;
// Create the Capture Graph Builder.
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild);
if (SUCCEEDED(hr))
{
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
// Initialize the Capture Graph Builder.
pBuild->SetFiltergraph(pGraph);
// Return both interface pointers to the caller.
*ppBuild = pBuild;
*ppGraph = pGraph; // The caller must release both interfaces.
pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pMediaControl);//通过此函数来查询某个组件是否支持某个特定的接口,如果支持就返回这些接口的指针
pGraph->QueryInterface(IID_IVideoWindow, (void **)&m_pVW);//通过此函数来查询某个组件是否支持某个特定的接口,如果支持就返回这些接口的指针
return S_OK;
}
else
{
pBuild->Release();
}
}
return hr; // Failed
}
//选择设备,并获取Video Capture Filter
void CGetDeviceInfoDlg::CreateVideoFilter(CString strSelectedDevice, IBaseFilter **pBaseFilter)
{
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
IEnumMoniker *pEm = NULL;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
if (hr != NOERROR)
return;
ULONG cFetched;
IMoniker *pM = NULL;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
IPropertyBag *pBag=0;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr == NOERROR)
{
//获取设备名称
char camera_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1, camera_name, sizeof(camera_name) ,"",NULL);
CString str(camera_name);
SysFreeString(var.bstrVal);
if (strSelectedDevice == str)
{
hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pBaseFilter);//就是这句获得Filter
if (FAILED(hr))
{
OutputDebugString(_T("BindToObject Failed"));
}
}
}
pBag->Release();
}
pM->Release();
}
pEm->Release();
pCreateDevEnum->Release();
}
void CGetDeviceInfoDlg::CreateAudioFilter(CString strSelectedDevice, IBaseFilter **pBaseFilter)
{
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
IEnumMoniker *pEm = NULL;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEm, 0);
if (hr != NOERROR)
return;
ULONG cFetched;
IMoniker *pM = NULL;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
IPropertyBag *pBag=0;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL); //还有其他属性,像描述信息等等...
if(hr == NOERROR)
{
//获取设备名称
char camera_name[1024];
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1, camera_name, sizeof(camera_name) ,"",NULL);
CString str(camera_name);
SysFreeString(var.bstrVal);
if (strSelectedDevice == str)
{
hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pBaseFilter);//就是这句获得Filter
if (FAILED(hr))
{
OutputDebugString(_T("BindToObject Failed"));
}
}
}
pBag->Release();
}
pM->Release();
}
pEm->Release();
pCreateDevEnum->Release();
}
void CGetDeviceInfoDlg::OnBnClickedBtnInit()
{
//1 选择视频采集设备
int nIndex = m_cbxCtrl.GetCurSel();
if (nIndex < 0)
{
MessageBox(_T("请选择视频设备"), _T("提示"));
return;
}
CString strDeviceName = _T("");
m_cbxCtrl.GetLBText(nIndex, strDeviceName);
if (strDeviceName.IsEmpty())
{
MessageBox(_T("获取视频设备名称为空"), _T("提示"));
return;
}
//选择设备,并获取Video Capture Filter
CreateVideoFilter(strDeviceName, &m_pVideoFilter);
if (m_pVideoFilter == NULL)
{
MessageBox(_T("获取m_pVideoFilter失败"), _T("提示"));
return;
}
//2 选择音频设备
int nAIndex = m_cbxAudioCtrl.GetCurSel();
if (nAIndex < 0)
{
MessageBox(_T("请选择音频设备"), _T("提示"));
return;
}
CString strAudioDeviceName = _T("");
m_cbxAudioCtrl.GetLBText(nAIndex, strAudioDeviceName);
if (strAudioDeviceName.IsEmpty())
{
MessageBox(_T("获取音频设备名称为空"), _T("提示"));
return;
}
//选择设备,并获取Audio Capture Filter
CreateAudioFilter(strAudioDeviceName, &m_pAudioFilter);
if (m_pAudioFilter == NULL)
{
MessageBox(_T("获取m_pAudioFilter失败"), _T("提示"));
return;
}
//创建视频捕捉实例
HRESULT hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&m_pGrabberFilter);
if (m_pGrabberFilter == NULL)
{
MessageBox(_T("获取m_pGrabberFilter失败"), _T("提示"));
return;
}
//创建采集过滤器图表
hr = InitCaptureGraphBuilder(&m_pGraphBuilder, &m_pCapture);
if (S_OK != hr || m_pGraphBuilder == NULL)
{
MessageBox(_T("创建IGraphBuilder和ICaptureGraphBuilder2接口失败"), _T("提示"));
return;
}
//将获取到的采集过滤器加入图表
hr = m_pGraphBuilder->AddFilter(m_pVideoFilter, L"Video Capture Filter");
if (S_OK != hr)
{
MessageBox(_T("把m_pVideoFilter添加到IGraphBuilder失败"), _T("提示"));
return;
}
//将视频捕捉过滤器加入图表
hr = m_pGraphBuilder->AddFilter(m_pGrabberFilter, L"Grabber");
if(S_OK != hr)
{
MessageBox(_T("Fail to put sample grabber in graph"));
return;
}
hr = m_pGraphBuilder->AddFilter(m_pAudioFilter, L"Audio Capture Filter");
if (S_OK != hr)
{
MessageBox(_T("把m_pAudioFilter添加到IGraphBuilder失败"), _T("提示"));
return;
}
GetVideoResolution();
}
//开始预览
void CGetDeviceInfoDlg::OnBnClickedBtnPreview()
{
if (m_bIsVideoOpen)
{
return;
}
if (!m_bRendered)
{
//选择一个分辨率
int nSel = m_cbxResolutionCtrl.GetCurSel();
if (nSel < 0)
{
MessageBox(_T("请选择一个分辨率"), _T("提示"));
return;
}
CString strResolution = _T("");
m_cbxResolutionCtrl.GetLBText(nSel, strResolution);
if (strResolution.IsEmpty())
{
MessageBox(_T("请选择一个有值分辨率"), _T("提示"));
return;
}
int nSetWidth = -1;
int nSetHeight = -1;
int nFindValue = strResolution.Find(_T("*"));
if (nFindValue > 0)
{
nSetWidth = _ttoi(strResolution.Left(nFindValue));
nSetHeight = _ttoi(strResolution.Mid(nFindValue + 1));
}
int nResolutionIndex = 0; //默认为0,即当前默认分辨率
for (int i = 0; i < m_arrCamResolutionArr.GetSize(); i++)
{
CamResolutionInfo camInfo = m_arrCamResolutionArr.GetAt(i);
if (camInfo.nWidth = nSetWidth && camInfo.nHeight == nSetHeight)
{
nResolutionIndex = camInfo.nResolutionIndex;
break;
}
}
//设置视频分辨率、格式
IAMStreamConfig *pConfig = NULL;
m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
m_pVideoFilter, IID_IAMStreamConfig, (void **) &pConfig);
AM_MEDIA_TYPE *pmt = NULL;
VIDEO_STREAM_CONFIG_CAPS scc;
pConfig->GetStreamCaps(nResolutionIndex, &pmt, (BYTE*)&scc);
VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)pmt->pbFormat;
if (pvi->AvgTimePerFrame < 500000)
pvi->AvgTimePerFrame = 500000;//设置帧率 (20帧每秒)
pConfig->SetFormat(pmt);//马上设置,才能起效果
m_pGrabberFilter->QueryInterface(IID_ISampleGrabber, (void **)&m_pGrabber);
pmt->majortype = MEDIATYPE_Video;
pmt->subtype = MEDIASUBTYPE_RGB24; //抓取24位位图
HRESULT hr = m_pGrabber->SetMediaType(pmt);
if(FAILED(hr))
{
AfxMessageBox(_T("Fail to set media type!"));
return;
}
////是否缓存数据,缓存的话,可以给后面做其他处理,不缓存的话,图像处理就放在回调中
//m_pGrabber->SetBufferSamples( TRUE );
//是否缓存数据,缓存的话,可以给后面做其他处理,不缓存的话,图像处理就放在回调中
m_pGrabber->SetBufferSamples(FALSE);
m_pGrabber->SetOneShot(FALSE);
m_pGrabber->SetCallback(&mCB, 1);
IBaseFilter *pMux = NULL;
IFileSinkFilter *pSink = NULL;
//hr = m_pCapture->SetOutputFileName(
// &MEDIASUBTYPE_Avi, // Specifies AVI for the target file. MEDIASUBTYPE_Avi
// L"D:\\JYSoft\\temp\\myvideo.avi", // File name.
// &pMux, // Receives a pointer to the mux.
// &pSink); // (Optional) Receives a pointer to the file sink.
hr = m_pCapture->SetOutputFileName(
&MEDIASUBTYPE_Asf, // Specifies WMV for the target file. MEDIASUBTYPE_Asf
L"D:\\JYSoft\\temp\\myvideo.wmv", // File name.
&pMux, // Receives a pointer to the mux.
&pSink); // (Optional) Receives a pointer to the file sink.
//如果要录制多段,可以用下面的语句重命名文件,就能生成新的文件
//pSink->SetFileName(L"D:\\JYSoft\\temp\\Example", pmt);
IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
pConfigMux->SetMasterStream(1);
}
//加入图表
m_pGraphBuilder->AddFilter(pMux, L"Video Filter");
/*
第一个参数设置成
PIN_CATEGORY_PREVIEW 或 PIN_CATEGORY_CAPTURE 结果会不一样,
设置成 PIN_CATEGORY_PREVIEW ,回调函数BufferCB的时间为空
设置成 PIN_CATEGORY_CAPTURE ,回调函数BufferCB的时间不为空,为抓取图像的时间
不过 设置成 PIN_CATEGORY_CAPTURE 的话,在一部分机器,摄像头画面会有卡顿情况出现。
*/
hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVideoFilter, m_pGrabberFilter, NULL);
if( FAILED(hr))
{
AfxMessageBox(_T("RenderStream failed"));
return;
}
//视频音频都要连到pMux上
m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVideoFilter, NULL, pMux);
m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudioFilter, NULL, pMux);
if (pConfigMux)
{
pConfigMux->Release();
}
pMux->Release();
//设置视频显示窗口
m_hShowWnd = GetDlgItem(IDC_STC_SHOW)->m_hWnd ; //picture控件的句柄
hr = m_pVW->put_Owner((OAHWND)m_hShowWnd);
if (FAILED(hr))
return;
hr = m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
if (FAILED(hr))
return;
//让图像充满整个窗口
if (m_pVW)
{
CRect rc;
::GetClientRect(m_hShowWnd,&rc);
m_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);
}
hr = m_pVW->put_Visible(OATRUE);
m_bRendered = TRUE;
}
//开始
HRESULT hr = m_pMediaControl->Run();
if(FAILED(hr))
{
AfxMessageBox(_T("Couldn't run the graph!"));
return;
}
m_bIsVideoOpen = TRUE;
}
//停止
void CGetDeviceInfoDlg::OnBnClickedBtnStop()
{
if (m_pMediaControl)
{
//停止
m_pMediaControl->Stop();
}
m_bIsVideoOpen = FALSE;
}
//释放
void CGetDeviceInfoDlg::OnDestroy()
{
CDialogEx::OnDestroy();
if (m_bIsVideoOpen)
{
// Stop media playback
if(m_pMediaControl)
{
m_pMediaControl->Stop();
}
if(m_pVW)
{
m_pVW->put_Visible(OAFALSE);
m_pVW->put_Owner(NULL);
}
SAFE_RELEASE(m_pCapture);
SAFE_RELEASE(m_pMediaControl);
SAFE_RELEASE(m_pGraphBuilder);
SAFE_RELEASE(m_pVideoFilter);
}
}
void CGetDeviceInfoDlg::GetVideoResolution()
{
if (m_pCapture)
{
m_arrCamResolutionArr.RemoveAll();
m_cbxResolutionCtrl.ResetContent();
IAMStreamConfig *pConfig = NULL;
//&MEDIATYPE_Video,如果包括其他媒体类型,第二个参数设置为0
HRESULT hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
m_pVideoFilter, IID_IAMStreamConfig, (void **)&pConfig);
int iCount = 0, iSize = 0;
hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
// Check the size to make sure we pass in the correct structure.
if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
{
// Use the video capabilities structure.
for (int iFormat = 0; iFormat < iCount; iFormat++)
{
VIDEO_STREAM_CONFIG_CAPS scc;
AM_MEDIA_TYPE *pmtConfig = NULL;
hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
if (SUCCEEDED(hr))
{
//(pmtConfig->subtype == MEDIASUBTYPE_RGB24) &&
if ((pmtConfig->majortype == MEDIATYPE_Video) &&
(pmtConfig->formattype == FORMAT_VideoInfo) &&
(pmtConfig->cbFormat >= sizeof (VIDEOINFOHEADER)) &&
(pmtConfig->pbFormat != NULL))
{
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
// pVih contains the detailed format information.
LONG lWidth = pVih->bmiHeader.biWidth;
LONG lHeight = pVih->bmiHeader.biHeight;
BOOL bFind = FALSE;
//是否已经存在这个分辨率,不存在就加入array
for (int n=0; n < m_arrCamResolutionArr.GetSize(); n++)
{
CamResolutionInfo sInfo = m_arrCamResolutionArr.GetAt(n);
if (sInfo.nWidth == lWidth && sInfo.nHeight == lHeight)
{
bFind = TRUE;
break;
}
}
if (!bFind)
{
CamResolutionInfo camInfo;
camInfo.nResolutionIndex = iFormat;
camInfo.nWidth = lWidth;
camInfo.nHeight = lHeight;
m_arrCamResolutionArr.Add(camInfo);
CString strFormat = _T("");
strFormat.Format(_T("%d * %d"), lWidth, lHeight);
m_cbxResolutionCtrl.AddString(strFormat);
}
}
// Delete the media type when you are done.
FreeMediaType(pmtConfig);
}
}
}
if (m_cbxResolutionCtrl.GetCount() > 0)
{
m_cbxResolutionCtrl.SetCurSel(0);
}
}
}
void CGetDeviceInfoDlg::FreeMediaType(AM_MEDIA_TYPE *pmt)
{
if (pmt == NULL)
{
return;
}
if (pmt->cbFormat != 0)
{
CoTaskMemFree((PVOID)pmt->pbFormat);
// Strictly unnecessary but tidier
pmt->cbFormat = 0;
pmt->pbFormat = NULL;
}
if (pmt->pUnk != NULL)
{
pmt->pUnk->Release();
pmt->pUnk = NULL;
}
}
void CGetDeviceInfoDlg::OnBnClickedBtnTakepic()
{
//获取抓取buffer大小
long nBufferSize = 0;
HRESULT hr = m_pGrabber->GetCurrentBuffer(&nBufferSize, NULL);
if(FAILED(hr))
{
AfxMessageBox(_T("Get BufferSize failed"));
return;
}
//获取抓取的data数据
BYTE *pBuffer = new BYTE[nBufferSize];
hr = m_pGrabber-> GetCurrentBuffer(&nBufferSize, (long*)pBuffer);
if(FAILED(hr))
{
AfxMessageBox(_T("Get BufferData failed"));
}
AM_MEDIA_TYPE mt;
hr = m_pGrabber->GetConnectedMediaType(&mt);
VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
int nWidth = vih->bmiHeader.biWidth;
int nHeight = vih->bmiHeader.biHeight;
FreeMediaType(&mt);
//生成图片
CTime cTime = CTime::GetCurrentTime();
CString strTime = cTime.Format(_T("%Y%m%d_%H%M%S.bmp"));
CString strFullPath = _T("");
strFullPath.Format(_T("D:\\JYSoft\\temp\\%s"), strTime);
//文件头
BITMAPFILEHEADER bfh;
memset(&bfh, 0, sizeof(bfh));
bfh.bfType = 'MB';
bfh.bfSize = sizeof(bfh) + nBufferSize + sizeof(BITMAPINFOHEADER);
bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
//格式信息
BITMAPINFOHEADER bih;
memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biWidth = nWidth;
bih.biHeight = nHeight;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = BI_RGB; //非压缩
CFile file;
if(file.Open(strFullPath, CFile::modeWrite | CFile::modeCreate))
{
//写入文件
file.Write((LPSTR)&bfh,sizeof(BITMAPFILEHEADER));
file.Write((LPSTR)&bih,sizeof(BITMAPINFOHEADER));
file.Write(pBuffer, nBufferSize);
file.Close();
}
//用完释放
delete[] pBuffer;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/poisson/DShowCaptureToLocal.git
git@gitee.com:poisson/DShowCaptureToLocal.git
poisson
DShowCaptureToLocal
DShowCaptureToLocal
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385