// CaptureVideo.cpp: implementation of the CCaptureVideo class. // ////////////////////////////////////////////////////////////////////// #include "CaptureVideo.h" #include #pragma comment(lib, "strmiids.lib") #pragma comment(lib, "strmbase.lib") ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCaptureVideo::CCaptureVideo() { if(FAILED(CoInitialize(NULL))) /*, COINIT_APARTMENTTHREADED)))*/ return; m_pCapture = NULL; m_pGB = NULL; m_pMC = NULL; m_pBF = NULL; m_pGrabber = NULL; m_pNullRenderer = NULL; m_nWidth = 0; m_nHeight = 0; m_bIsStarted = FALSE; m_pEnc = NULL; } CCaptureVideo::~CCaptureVideo() { if (m_pEnc) { if (m_bIsStarted) { m_pEnc->Close(); } delete m_pEnc ; m_pEnc = NULL; Stop(); } CoUninitialize(); } LPBITMAPINFO CCaptureVideo::GetBmpInfo() { return mCB.GetBmpInfo(); } void CCaptureVideo::SendEnd() //发送结束 设置可以再取数据 { InterlockedExchange((LPLONG)&mCB.bStact,CMD_CAN_COPY); //原子自增可以发送 //原子自减 发送完毕 可以copy } LPBYTE CCaptureVideo::GetDIB(DWORD& nSize) { BYTE *buf = NULL; if (mCB.bStact==CMD_CAN_SEND) //这里改变了一下发送的状态 { buf = mCB.GetNextScreen(nSize); } if (buf == NULL) return NULL; return m_pEnc->Encode(buf,nSize); } HRESULT CCaptureVideo::InitCaptureGraphBuilder() { HRESULT hr; // 创建IGraphBuilder接口 hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB); // 创建ICaptureGraphBuilder2接口 hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &m_pCapture); if (FAILED(hr)) return hr; m_pCapture->SetFiltergraph(m_pGB); hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC); if (FAILED(hr)) return hr; return hr; } bool CCaptureVideo::BindFilter(int deviceId, IBaseFilter **pFilter) { if (deviceId < 0) return false; // 举所有视频捕捉设备 CComPtr pCreateDevEnum; HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum); if (hr != NOERROR) return false; CComPtr pEm; hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0); if (hr != NOERROR) return false; pEm->Reset(); ULONG cFetched; IMoniker *pM; int index = 0; while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK, index <= deviceId) { IPropertyBag *pBag; 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) { if (index == deviceId) { pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter); } SysFreeString(var.bstrVal); } pBag->Release(); } pM->Release(); index++; } return true; } void CCaptureVideo::FreeMediaType(AM_MEDIA_TYPE& mt) { if (mt.cbFormat != 0) { CoTaskMemFree((PVOID)mt.pbFormat); // Strictly unnecessary but tidier mt.cbFormat = 0; mt.pbFormat = NULL; } if (mt.pUnk != NULL) { mt.pUnk->Release(); mt.pUnk = NULL; } } HRESULT CCaptureVideo::Start(int iDeviceID, HWND hWnd , int width, int height) { HRESULT hr; hr = InitCaptureGraphBuilder(); if (FAILED(hr)) return hr; // 绑定设备过滤器。我们知道设备因为id if(!BindFilter(iDeviceID, &m_pBF)) return S_FALSE; hr = m_pGB->AddFilter(m_pBF, L"Capture Filter"); // create a sample grabber hr = CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_ISampleGrabber, (void**)&m_pGrabber ); if(FAILED(hr)) return hr; hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (LPVOID*) &m_pNullRenderer); if(FAILED(hr)) return hr; hr = m_pGB->AddFilter(m_pNullRenderer, L"NullRenderer"); CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabBase( m_pGrabber ); //设置视频格式 AM_MEDIA_TYPE mt; ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); mt.majortype = MEDIATYPE_Video; mt.subtype = MEDIASUBTYPE_RGB24; // MEDIASUBTYPE_RGB24 ; hr = m_pGrabber->SetMediaType(&mt); if( FAILED(hr) ) { return hr; } hr = m_pGB->AddFilter( pGrabBase, L"Grabber" ); if( FAILED( hr ) ) { return hr; } IAMStreamConfig *pConfig; hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Interleaved,m_pBF,IID_IAMStreamConfig,(void **)&pConfig); if( hr != NOERROR ) { hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,m_pBF,IID_IAMStreamConfig,(void **)&pConfig); if(hr != NOERROR) return hr; } m_nWidth = width; m_nHeight = height; AM_MEDIA_TYPE *mmt = NULL; hr = pConfig-> GetFormat(&mmt); VIDEOINFOHEADER *vvih = (VIDEOINFOHEADER*)mmt->pbFormat; if(vvih == NULL) { return S_FALSE; } AM_MEDIA_TYPE *pmt = mmt; VIDEOINFOHEADER *pvih = (VIDEOINFOHEADER*)pmt->pbFormat; if(pvih == NULL) { return S_FALSE; } pvih->bmiHeader.biHeight=height; //修改采集视频的高为240 pvih->bmiHeader.biWidth=width; //修改采集视频的宽为320 pvih->AvgTimePerFrame = 10000000/10; pmt->pbFormat = (unsigned char*)pvih; hr = pConfig->SetFormat(pmt); //重新设置参数 if(FAILED(hr)) { return hr; } SAFE_RELEASE(pConfig); // try to render preview/capture pin hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF,pGrabBase,m_pNullRenderer); if( FAILED( hr ) ) { hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pGrabBase,m_pNullRenderer); if( FAILED( hr ) ) return hr; } mCB.lWidth = width; mCB.lHeight = height; FreeMediaType(mt); hr = m_pGrabber->SetBufferSamples( FALSE ); hr = m_pGrabber->SetOneShot( FALSE ); hr = m_pGrabber->SetCallback( &mCB, 1 );//设置视频捕获回调函数 也就是如果有视频数据时就会调用这个类的BufferCB函数 m_pEnc = new CXvidEnc; if (m_pEnc == NULL) { return S_FALSE; } m_pEnc->AttachCaller(mCB.lWidth, mCB.lHeight) ; m_pEnc->XVID_GLOBAL_INIT() ; m_pEnc->Open(); m_bIsStarted = TRUE; hr = m_pMC->Run();//开始视频捕捉 if(FAILED(hr)) { return hr; // 失败 } return S_OK; } HRESULT CCaptureVideo::Stop() { if(m_pMC) m_pMC->Stop(); // m_pMC->StopWhenReady(); SAFE_RELEASE(m_pMC); SAFE_RELEASE(m_pGB); SAFE_RELEASE(m_pBF); SAFE_RELEASE(m_pNullRenderer); SAFE_RELEASE(m_pGrabber); SAFE_RELEASE(m_pCapture); m_pMC = NULL; m_pGB = NULL; m_pBF = NULL; m_pNullRenderer = NULL; m_pGrabber = NULL; m_pCapture = NULL; return S_OK ; } int CCaptureVideo::EnumDevices(DeviceInfo *head) { if (!head) return 0; DeviceInfo *ptr = head; int id = 0;//枚举视频扑捉设备 //枚举视频扑捉设备 ICreateDevEnum *pCreateDevEnum; //ICreateDevEnum接口建立指定类型的列表 ICaptureGraphBuilder2 *pBuilder = NULL; IBaseFilter *pVCap = NULL; IAMStreamConfig *pVSC = NULL; HRESULT hr = CoCreateInstance((REFCLSID)CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, (REFIID)IID_ICaptureGraphBuilder2,(void **)&pBuilder); if (hr != NOERROR) return -1; //用指定的类标识符创建一个未初始化的对象,这里的参数为CLSID_SystemDeviceEnum即枚举设备的对象 hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum); if (hr != NOERROR) return -1; //指出要枚举那个类型的设备这里参数CLSID_VideoInputDeviceCategory枚举视频设备 CComPtr pEm; hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0); if (hr != NOERROR) return -1; pEm->Reset(); ULONG cFetched; IMoniker *pM; while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK) { IPropertyBag *pBag; 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 str[2048]; if (ptr->deviceId != -1) { ptr->next = new DeviceInfo(); ptr = ptr->next; } ptr->deviceId = id++; WideCharToMultiByte(CP_ACP,0,var.bstrVal, -1, str, 2048, NULL, NULL); ptr->friendlyName = str; SysFreeString(var.bstrVal); } pBag->Release(); } hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&pVCap); if(SUCCEEDED(hr)) { hr = pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,pVCap, IID_IAMStreamConfig, (void **)&pVSC); if(hr != NOERROR) { hr = pBuilder->FindInterface(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video, pVCap, IID_IAMStreamConfig, (void **)&pVSC); } if(SUCCEEDED(hr)) { int iCount = 0, iSize = 0; hr = pVSC->GetNumberOfCapabilities(&iCount, &iSize); ResolutionInfo** pRes = &(ptr->resInfo); if(iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) { for (int iFormat = 0; iFormat < iCount; iFormat++) { VIDEO_STREAM_CONFIG_CAPS scc; AM_MEDIA_TYPE *pmtConfig = NULL; hr = pVSC->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc); if (SUCCEEDED(hr)) { //分辨率 if(HEADER(pmtConfig->pbFormat)->biWidth != 0 && HEADER(pmtConfig->pbFormat)->biHeight != 0) { char cResolution[32] = {0}; sprintf(cResolution,"%d * %d:",HEADER(pmtConfig->pbFormat)->biWidth,HEADER(pmtConfig->pbFormat)->biHeight); *pRes = new ResolutionInfo; (*pRes)->Resolution = cResolution; pRes = &((*pRes)->next); } } } } pM->AddRef(); } } pM->Release(); } SAFE_RELEASE(pBuilder); SAFE_RELEASE(pVCap); SAFE_RELEASE(pVSC); return id; }