www.pudn.com > 摄像头捕获C++类.rar > MyCapVideo.cpp
//MyCapVideo.cpp #include "stdafx.h" #include "MyCapVideo.h" #include#pragma comment (lib, "Strmiids.lib") #pragma comment (lib, "Quartz.lib") MyCapVideo::MyCapVideo() { CoInitialize(NULL); pBuilder=NULL; pFg=NULL; pVCap=NULL; pACap=NULL; pVCP=NULL ; pACP=NULL; //压缩 pAM=NULL; //Avi Muxer pFW=NULL; //File Writter pSink=NULL; pRender=NULL; pConfigAviMux=NULL; pVW=NULL; pMC=NULL; pME=NULL; pDF=NULL; pVC=NULL; pDlg=NULL; pASC=NULL; // for audio cap pVSC=NULL; // for video cap bGraphBuilt=false; SetCapDevice(); GetInterfaces(); } MyCapVideo::~MyCapVideo() { CloseInterfaces(); CoUninitialize(); } HRESULT MyCapVideo::AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) { IMoniker * pMoniker; IRunningObjectTable *pROT; WCHAR wsz[128]; HRESULT hr; if (!pUnkGraph || !pdwRegister) return E_POINTER; if (FAILED(GetRunningObjectTable(0, &pROT))) return E_FAIL; wsprintfW(wsz, L"FilterGraph %08x pid %08x\0", (DWORD_PTR)pUnkGraph, GetCurrentProcessId()); hr = CreateItemMoniker(L"!", wsz, &pMoniker); if (SUCCEEDED(hr)) { // Use the ROTFLAGS_REGISTRATIONKEEPSALIVE to ensure a strong reference // to the object. Using this flag will cause the object to remain // registered until it is explicitly revoked with the Revoke() method. // // Not using this flag means that if GraphEdit remotely connects // to this graph and then GraphEdit exits, this object registration // will be deleted, causing future attempts by GraphEdit to fail until // this application is restarted or until the graph is registered again. hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, pMoniker, pdwRegister); pMoniker->Release(); } pROT->Release(); return hr; } // Removes a filter graph from the Running Object Table void MyCapVideo::RemoveGraphFromRot(DWORD pdwRegister) { IRunningObjectTable *pROT; if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) { pROT->Revoke(pdwRegister); pROT->Release(); } } void MyCapVideo::SetCapDevice() { this->pACap=NULL; this->pACP=NULL; this->pVCap=NULL; this->pVCP=NULL; EnumFilters(EnumAudioCapFilter, SetAudioDevice); EnumFilters(EnumAudioCompressFilter, SetAudioCompress); EnumFilters(EnumVideoCapFilter, SetVideoDevice); EnumFilters(EnumVideoCompressFilter, SetVideoCompress); } bool SetAudioDevice(MyCapVideo *m_cap,IBaseFilter *pFilter,CString Name) { m_cap->pACap=pFilter; return false; } bool SetAudioCompress(MyCapVideo *m_cap,IBaseFilter *pFilter,CString Name) { m_cap->pACP=pFilter; if(Name.Compare("MPEG Layer-3")==0) { m_cap->pACP=pFilter; return false; } if(Name.Compare("Windows Media Audio V2")==0) { m_cap->pACP=pFilter; return false; } return true; } bool SetVideoDevice(MyCapVideo *m_cap,IBaseFilter *pFilter,CString Name) { m_cap->pVCap=pFilter; return false; } bool SetVideoCompress(MyCapVideo *m_cap,IBaseFilter *pFilter,CString Name) { m_cap->pVCP=pFilter; if(Name.Left(4).Compare("DivX")==0) { m_cap->pVCP=pFilter; return false; } if(Name.Compare("ffdshow Video Codec")==0) { m_cap->pVCP=pFilter; return false; } if(Name.Compare("Microsoft Windows Media Video 9")==0) { m_cap->pVCP=pFilter; return false; } return true; } HRESULT MyCapVideo::GetInterfaces(void) { HRESULT hr; bGraphBuilt=false; CloseInterfaces(); wCapFileSize=1; //20M // 创建CaptureGraphBuilder hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **)&pBuilder); if (FAILED(hr)) return hr; //创建Filter Graph hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&pFg); if (FAILED(hr)) return hr; hr = pBuilder->SetFiltergraph(pFg); if (FAILED(hr)) return hr; //获得视频控制,窗口,事件接口 hr = pFg->QueryInterface(IID_IMediaControl,(LPVOID *) &pMC); if (FAILED(hr)) return hr; hr = pFg->QueryInterface(IID_IVideoWindow, (LPVOID *) &pVW); if (FAILED(hr)) return hr; hr = pFg->QueryInterface(IID_IMediaEvent, (LPVOID *) &pME); if (FAILED(hr)) return hr; // Set the window handle used to process graph events //hr = g_pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0); return hr; } void MyCapVideo::CloseInterfaces() { SAFE_RELEASE(pMC); SAFE_RELEASE(pME); SAFE_RELEASE(pVW); SAFE_RELEASE(pFg); SAFE_RELEASE(pBuilder); } HRESULT MyCapVideo::ConnectFilters(IBaseFilter* pUpFilter, IBaseFilter* pDownFilter) { if( !pUpFilter || !pDownFilter ) { return E_INVALIDARG; } // All the need pin & pin enumerator pointers CComPtr pEnumUpFilterPins , pEnumDownFilterPins; CComPtr pUpFilterPin , pDownFilterPin; HRESULT hr = S_OK; // Get the pin enumerators for both the filtera hr = pUpFilter->EnumPins(&pEnumUpFilterPins); if( FAILED( hr ) ) { return hr; } hr= pDownFilter->EnumPins(&pEnumDownFilterPins); if( FAILED( hr ) ) { return hr; } // Loop on every pin on the Upstream Filter BOOL bConnected = FALSE; PIN_DIRECTION pinDir; ULONG nFetched = 0; //while(pUpFilterPin.Release( ), S_OK == pEnumUpFilterPins->Next(1, &pUpFilterPin, &nFetched) ) while(S_OK == pEnumUpFilterPins->Next(1, &pUpFilterPin, &nFetched) ) { // Make sure that we have the output pin of the upstream filter hr = pUpFilterPin->QueryDirection( &pinDir ); if( FAILED( hr ) || PINDIR_INPUT == pinDir ) { continue; } // // I have an output pin; loop on every pin on the Downstream Filter // //while(pDownFilterPin.Release( ), S_OK == pEnumDownFilterPins->Next(1, &pDownFilterPin, &nFetched) ) while( S_OK == pEnumDownFilterPins->Next(1, &pDownFilterPin, &nFetched) ) { hr = pDownFilterPin->QueryDirection( &pinDir ); if( FAILED( hr ) || PINDIR_OUTPUT == pinDir ) { continue; } // Try to connect them and exit if u can else loop more until you can if(SUCCEEDED(pFg->ConnectDirect(pUpFilterPin, pDownFilterPin, NULL))) { bConnected = TRUE; break; } } hr = pEnumDownFilterPins->Reset(); if( FAILED( hr ) ) { return hr; } } if( !bConnected ) { return E_FAIL; } return S_OK; } int MyCapVideo::EnumFilters(EnumType enum_type, bool Visit(MyCapVideo *m_cap,IBaseFilter *,CString Name)) { HRESULT hr; int nFilters=0; ICreateDevEnum * m_pSysDevEnum=NULL; IEnumMoniker *pEnumCat = NULL; const CLSID *clsid; IBaseFilter *pTmpFilter; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&m_pSysDevEnum); if FAILED(hr) return nFilters; switch(enum_type) { case EnumAudioCapFilter: clsid = &CLSID_AudioInputDeviceCategory; break; case EnumAudioCompressFilter: clsid = &CLSID_AudioCompressorCategory; break; case EnumVideoCapFilter: clsid = &CLSID_VideoInputDeviceCategory; break; case EnumVideoCompressFilter: clsid = &CLSID_VideoCompressorCategory; break; } hr = m_pSysDevEnum->CreateClassEnumerator(*clsid, &pEnumCat, 0); //ASSERT(SUCCEEDED(hr)); if FAILED(hr) return nFilters; IMoniker *pMoniker; ULONG cFetched; VARIANT varName={0}; // Enumerate all items associated with the moniker while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag *pPropBag; //ASSERT(pMoniker); hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); //ASSERT(SUCCEEDED(hr)); //ASSERT(pPropBag); if (FAILED(hr)) continue; varName.vt = VT_BSTR; hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (FAILED(hr)) continue; // Get filter name (converting BSTR name to a CString) CString str(varName.bstrVal); SysFreeString(varName.bstrVal); // CLSID 没有用处都是一样的 /* VARIANT varFilterClsid; varFilterClsid.vt = VT_BSTR; CLSID clsidFilter; // Read CLSID string from property bag hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0); if (FAILED(hr)) continue; if(CLSIDFromString(varFilterClsid.bstrVal, &clsidFilter) == S_FALSE) continue; CString clsid(varFilterClsid.bstrVal); SysFreeString(varFilterClsid.bstrVal); */ //得到Filter hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pTmpFilter); if (FAILED(hr)) continue; nFilters++; // Cleanup interfaces SAFE_RELEASE(pPropBag); SAFE_RELEASE(pMoniker); if(!Visit(this,pTmpFilter,str)) //=True 继续枚举 { return nFilters; } //if( MessageBox(0,str,"是否采用该音频输入设备",MB_YESNO|MB_ICONQUESTION)==IDYES) //return nFilters; } return nFilters; } /* int MyCapVideo::EnumAudioCapFilters(IBaseFilter **pACap,CString &Name) { HRESULT hr; int nFilters=0; ICreateDevEnum * m_pSysDevEnum=NULL; IEnumMoniker *pEnumCat = NULL; const CLSID *clsid; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&m_pSysDevEnum); if FAILED(hr) return nFilters; clsid = &CLSID_AudioInputDeviceCategory; hr = m_pSysDevEnum->CreateClassEnumerator(*clsid, &pEnumCat, 0); ASSERT(SUCCEEDED(hr)); if FAILED(hr) return nFilters; // Enumerate all filters using the category enumerator //hr = EnumFilters(pEnumCat); IMoniker *pMoniker; ULONG cFetched; VARIANT varName={0}; // Enumerate all items associated with the moniker while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag *pPropBag; ASSERT(pMoniker); hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); ASSERT(SUCCEEDED(hr)); ASSERT(pPropBag); if (FAILED(hr)) continue; varName.vt = VT_BSTR; hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (FAILED(hr)) continue; // Get filter name (converting BSTR name to a CString) CString str(varName.bstrVal); SysFreeString(varName.bstrVal); nFilters++; Name=str; VARIANT varFilterClsid; varFilterClsid.vt = VT_BSTR; hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pACap); // Cleanup interfaces SAFE_RELEASE(pPropBag); SAFE_RELEASE(pMoniker); if( MessageBox(0,str,"是否采用该音频输入设备",MB_YESNO|MB_ICONQUESTION)==IDYES) return nFilters; } return nFilters; } int MyCapVideo::EnumAudioCompressFilters(IBaseFilter **pACP,CString &Name) { HRESULT hr; int nFilters=0; ICreateDevEnum * m_pSysDevEnum=NULL; IEnumMoniker *pEnumCat = NULL; const CLSID *clsid; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&m_pSysDevEnum); if FAILED(hr) return nFilters; clsid = &CLSID_AudioCompressorCategory; hr = m_pSysDevEnum->CreateClassEnumerator(*clsid, &pEnumCat, 0); ASSERT(SUCCEEDED(hr)); if FAILED(hr) return nFilters; // Enumerate all filters using the category enumerator //hr = EnumFilters(pEnumCat); IMoniker *pMoniker; ULONG cFetched; VARIANT varName={0}; // Enumerate all items associated with the moniker while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag *pPropBag; ASSERT(pMoniker); hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); ASSERT(SUCCEEDED(hr)); ASSERT(pPropBag); if (FAILED(hr)) continue; varName.vt = VT_BSTR; hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (FAILED(hr)) continue; // Get filter name (converting BSTR name to a CString) CString str(varName.bstrVal); SysFreeString(varName.bstrVal); nFilters++; Name=str; VARIANT varFilterClsid; varFilterClsid.vt = VT_BSTR; hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pACP); // Cleanup interfaces SAFE_RELEASE(pPropBag); SAFE_RELEASE(pMoniker); if( MessageBox(0,str,"是否采用这种音频压缩方式",MB_YESNO|MB_ICONQUESTION)==IDYES) return nFilters; } return nFilters; } int MyCapVideo::EnumVideoCapFilters(IBaseFilter **pVCap,CString &Name) { HRESULT hr; int nFilters=0; ICreateDevEnum * m_pSysDevEnum=NULL; IEnumMoniker *pEnumCat = NULL; const CLSID *clsid; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&m_pSysDevEnum); if FAILED(hr) return nFilters; clsid = &CLSID_VideoInputDeviceCategory; hr = m_pSysDevEnum->CreateClassEnumerator(*clsid, &pEnumCat, 0); ASSERT(SUCCEEDED(hr)); if FAILED(hr) return nFilters; // Enumerate all filters using the category enumerator //hr = EnumFilters(pEnumCat); IMoniker *pMoniker; ULONG cFetched; VARIANT varName={0}; // Enumerate all items associated with the moniker while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag *pPropBag; ASSERT(pMoniker); hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); ASSERT(SUCCEEDED(hr)); ASSERT(pPropBag); if (FAILED(hr)) continue; varName.vt = VT_BSTR; hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (FAILED(hr)) continue; // Get filter name (converting BSTR name to a CString) CString str(varName.bstrVal); SysFreeString(varName.bstrVal); nFilters++; Name=str; VARIANT varFilterClsid; varFilterClsid.vt = VT_BSTR; hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pVCap); // Cleanup interfaces SAFE_RELEASE(pPropBag); SAFE_RELEASE(pMoniker); if( MessageBox(0,str,"是否采用该视频输入设备",MB_YESNO|MB_ICONQUESTION)==IDYES) return nFilters; } return nFilters; } int MyCapVideo::EnumVideoCompressFilters(IBaseFilter **pVCP,CString &Name) { HRESULT hr; int nFilters=0; ICreateDevEnum * m_pSysDevEnum=NULL; IEnumMoniker *pEnumCat = NULL; const CLSID *clsid; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&m_pSysDevEnum); if FAILED(hr) return nFilters; clsid = &CLSID_VideoCompressorCategory; hr = m_pSysDevEnum->CreateClassEnumerator(*clsid, &pEnumCat, 0); ASSERT(SUCCEEDED(hr)); if FAILED(hr) return nFilters; // Enumerate all filters using the category enumerator //hr = EnumFilters(pEnumCat); IMoniker *pMoniker; ULONG cFetched; VARIANT varName={0}; // Enumerate all items associated with the moniker while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag *pPropBag; ASSERT(pMoniker); hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); ASSERT(SUCCEEDED(hr)); ASSERT(pPropBag); if (FAILED(hr)) continue; varName.vt = VT_BSTR; hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (FAILED(hr)) continue; // Get filter name (converting BSTR name to a CString) CString str(varName.bstrVal); SysFreeString(varName.bstrVal); nFilters++; Name=str; VARIANT varFilterClsid; varFilterClsid.vt = VT_BSTR; hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pVCP); // Cleanup interfaces SAFE_RELEASE(pPropBag); SAFE_RELEASE(pMoniker); if( MessageBox(0,str,"是否采用这种视频压缩方式",MB_YESNO |MB_ICONQUESTION)==IDYES) return nFilters; } return nFilters; } */ bool MyCapVideo::StopCapture() { if (pMC) pMC->StopWhenReady(); if (g_dwGraphRegister) RemoveGraphFromRot(g_dwGraphRegister); // Stop receiving events //if (pME) // pME->SetNotifyWindow(NULL, WM_GRAPHNOTIFY, 0); // Relinquish ownership (IMPORTANT!) of the video window. // Failing to call put_Owner can lead to assert failures within // the video renderer, as it still assumes that it has a valid // parent window. if(pVW) { pVW->put_Visible(OAFALSE); pVW->put_Owner(NULL); } return true; } bool MyCapVideo::CaptureToFile(LPTSTR AviFileName) { HRESULT hr; if(!szCaptureFile) return false; if(!pVCap && !pACap) return false; if(!bGraphBuilt) { //创建Avi Mux Filter hr = CoCreateInstance(CLSID_AviDest, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&pAM); hr = pFg->AddFilter(pAM, L"Avi Mixer Filter"); //新建一个FileWriter hr = CoCreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&pFW); hr = pFg->AddFilter(pFW, L"FileWriter Filter"); pFW->QueryInterface(IID_IFileSinkFilter,(void **)&pSink); //得到当前的Captuer Filter pMC->Stop(); hr = AddGraphToRot(pFg, &g_dwGraphRegister); if(pVCap) hr = pFg->AddFilter(pVCap, L"Capture Filter"); if(pVCP) hr = pFg->AddFilter(pVCP, L"Compress Filter"); if(pACap) hr = pFg->AddFilter(pACap, L"Audio Capture Filter"); if(pACP) hr = pFg->AddFilter(pACP, L"Audio Compress Filter"); //CFileDialog dlg1(1); //int ret=dlg1.DoModal(); //CString f1=dlg1.GetPathName() ; if(pVCap && pVCP) hr = ConnectFilters(pVCap,pVCP); if(pVCP && pAM) hr = ConnectFilters(pVCP,pAM); if(pACap && pACP) hr = ConnectFilters(pACap,pACP); if(pACP && pAM) hr = ConnectFilters(pACP,pAM); if(pAM && pFW) hr = ConnectFilters(pAM,pFW); } if(AviFileName) { wsprintf(szCaptureFile,"%s",AviFileName); WCHAR wach[_MAX_PATH]; MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szCaptureFile, -1, wach,_MAX_PATH); pSink->SetFileName(wach,NULL); } bGraphBuilt=true; pMC->Run(); return true; /* //设置文件,分配文件空间 CFileDialog dlg1(1); int ret=dlg1.DoModal(); CString f1=dlg1.GetPathName() ; //CString f1="d:\\test.avi"; if(!f1.IsEmpty()) { wsprintf(szCaptureFile,"%s",f1.GetBuffer(f1.GetLength())); WCHAR wach[_MAX_PATH]; MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szCaptureFile, -1, wach, _MAX_PATH); if (pBuilder->AllocCapFile(wach,wCapFileSize*100) != NOERROR) MessageBoxA( "Failed to pre-allocate capture file space", "Error", MB_OK | MB_ICONEXCLAMATION); else TRACE("分配文件空间 Ok %s!\r\n",szCaptureFile); } else { return; } //保存到文件 //建立Graph的渲染部分,并告诉他写文件(用先前决定的文件) //strcpy(szCaptureFile,"d:\\test.avi"); WCHAR wach[_MAX_PATH]; MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szCaptureFile, -1, wach,_MAX_PATH); GUID guid = MEDIASUBTYPE_Avi; hr = pBuilder->SetOutputFileName(&guid, wach, &pAM,NULL); if (hr != NOERROR) { AfxMessageBox("Error %x: Cannot set output file", hr); } else TRACE("SetOutputFileName Ok %s!\r\n",szCaptureFile); pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,pVCap,NULL,pAM); //pMux->Release(); */ }