directshow虚拟摄像头
2017-06-12 16:52
183 查看
window下directshow虚拟摄像头代码:
部分学习例子下载地址:http://download.csdn.net/detail/ab7936573/9868274
#pragma once #ifndef POINTER_64 #define POINTER_64 __ptr64 #endif #include <streams.h> #include <initguid.h> #include "LogPrint.h" #include "CCaptureVideo.h" #include "EvoPacket.h" #include "PacketPool.h" #include "EvoPacketAllocator.h" extern "C" const GUID CLSID_VirtualCamera; // {982434C1-D408-4984-A4D0-33DF357BD7ED} DEFINE_GUID(CLSID_VirtualCamera, 0x982434c1, 0xd408, 0x4984, 0xa4, 0xd0, 0x33, 0xdf, 0x35, 0x7b, 0xd7, 0xed); #define VirtualCamera_FilterName L"Virtual Camera (By evomotion)" class CVirtualSource : public CSource { public: static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr); STDMETHODIMP QueryInterface(REFIID riid, void **ppv); private: CVirtualSource(LPUNKNOWN lpunk, HRESULT *phr); CSourceStream *m_pPin; }; #define DECLARE_PTR(type, ptr, expr) type* ptr = (type*)(expr); const REFERENCE_TIME FPS_30 = UNITS / 30; const REFERENCE_TIME FPS_20 = UNITS / 20; const REFERENCE_TIME FPS_10 = UNITS / 10; const REFERENCE_TIME FPS_5 = UNITS / 5; const REFERENCE_TIME FPS_4 = UNITS / 4; const REFERENCE_TIME FPS_3 = UNITS / 3; const REFERENCE_TIME FPS_2 = UNITS / 2; const REFERENCE_TIME FPS_1 = UNITS / 1; const REFERENCE_TIME rtDefaultFrameLength = FPS_30; class CVirtualStream : public CSourceStream, public IAMStreamConfig, public IKsPropertySet, public CVideoFrameHandler { protected: int m_iImageHeight; // The current image height int m_iImageWidth; // And current image width int m_iFrameNumber; const REFERENCE_TIME m_rtFrameLength; //采集器 int m_nDeviceID; char * m_DeviceName; CCaptureVideo m_capture; //缓冲器 PacketPool pool; //当前数据 EvoPacket *m_packet; EvoPacket *m_lastPacket; //锁 CCritSec m_cSharedData; CCritSec m_cSharedState; // Protects our internal state IReferenceClock *m_pClock; REFERENCE_TIME m_rtStop; public: CVirtualStream(HRESULT *phr, CSource *pFilter); ~CVirtualStream(); ////////////////////////////////////////////////////////////////////////// // CBasePin ////////////////////////////////////////////////////////////////////////// // Quality control // Not implemented because we aren't going in real time. // If the file-writing filter slows the graph down, we just do nothing, which means // wait until we're unblocked. No frames are ever dropped. STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q); ////////////////////////////////////////////////////////////////////////// // IUnknown ////////////////////////////////////////////////////////////////////////// STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { if (riid == _uuidof(IAMStreamConfig)) *ppv = (IAMStreamConfig*)this; else if (riid == _uuidof(IKsPropertySet)) *ppv = (IKsPropertySet*)this; else return CSourceStream::QueryInterface(riid, ppv); AddRef(); return S_OK; } STDMETHODIMP_(ULONG) AddRef() { return GetOwner()->AddRef(); } STDMETHODIMP_(ULONG) Release() { return GetOwner()->Release(); } ////////////////////////////////////////////////////////////////////////// // CSourceStream ////////////////////////////////////////////////////////////////////////// // Override the version that offers exactly one media type HRESULT FillBuffer(IMediaSample *pSample); HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest); // Set the agreed media type and set up the necessary parameters HRESULT SetMediaType(const CMediaType *pMediaType); // Support multiple display formats HRESULT CheckMediaType(const CMediaType *pMediaType); HRESULT GetMediaType(int iPosition, CMediaType *pmt); ////////////////////////////////////////////////////////////////////////// // IAMStreamConfig ////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt); HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE **ppmt); HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int *piCount, int *piSize); HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC); ////////////////////////////////////////////////////////////////////////// // IKsPropertySet ////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwID, void *pInstanceData, DWORD cbInstanceData, void *pPropData, DWORD cbPropData); HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, void *pInstanceData, DWORD cbInstanceData, void *pPropData, DWORD cbPropData, DWORD *pcbReturned); HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport); ////////////////////////////////////////////////////////////////////////// // CVideoFrameHandler ////////////////////////////////////////////////////////////////////////// void VideoFrameData(double dblSampleTime, BYTE * pBuffer, long lBufferSize); private: //缓存模块 EvoPacket *PoolNew(uint32_t dataSize); void PoolDelete(EvoPacket **packet); void Delete(EvoPacket **packet); PacketPool *GetPool(); //填充彩虹条 void FillRainbowBar(char * buffer,int size,int width,int height); };
#include "VirtualSource.h" #include "EvoAttributeMemory.h" CUnknown * WINAPI CVirtualSource::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) { ASSERT(phr); DbgSetModuleLevel(LOG_MEMORY, 2); CUnknown *punk = new CVirtualSource(lpunk, phr); LLOG("CVirtualSource::CreateInstance:0x%X\n", punk); return punk; } CVirtualSource::CVirtualSource(LPUNKNOWN lpunk, HRESULT *phr) : CSource(VirtualCamera_FilterName, lpunk, CLSID_VirtualCamera) { ASSERT(phr); CAutoLock cAutoLock(&m_cStateLock); m_paStreams = new CSourceStream *[1]; m_paStreams[0] = m_pPin = new CVirtualStream(phr, this); m_iPins = 1; } STDMETHODIMP CVirtualSource::QueryInterface(REFIID riid, void **ppv) { if (riid == _uuidof(IAMStreamConfig) || riid == _uuidof(IKsPropertySet)) return m_paStreams[0]->QueryInterface(riid, ppv); else return CSource::QueryInterface(riid, ppv); } //设备名 static char * devicesName[] = { "Video Control", "Condor" }; //#include <gl/glew.h> //#pragma comment(lib,"glew32.lib") CVirtualStream::CVirtualStream(HRESULT *phr, CSource *pFilter) : CSourceStream(NAME("Push Source Desktop"), phr, pFilter, L"Out"), m_iFrameNumber(0), m_rtFrameLength(rtDefaultFrameLength), m_packet(NULL), m_lastPacket(NULL), m_nDeviceID(-1), m_DeviceName(NULL) { // Save dimensions for later use in FillBuffer() m_iImageWidth = 320; m_iImageHeight = 240; //搜索摄像设备并绑定 std::vector<std::string > devices; m_capture.EnumDevices(devices); int count = sizeof(devicesName) / sizeof(devicesName[0]); for (int i = 0; i < count; i++) { char * name = devicesName[i]; for (size_t j = 0; j < devices.size(); j++) { if (devices[j].compare(name) == 0) { HRESULT ret = m_capture.Open(j); if (ret == S_OK) { m_nDeviceID = j; m_DeviceName = name; break; } } } } if (m_nDeviceID != -1) { CSampleGrabberCB * cb = m_capture.GetSampleGrabberCB(); if (cb != NULL) { m_iImageWidth = cb->lWidth; m_iImageHeight = cb->lHeight; } m_capture.GrabVideoFrames(TRUE,this); m_capture.Play(); } //初始化默认视频类型 GetMediaType(0, &m_mt); CoCreateInstance(CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, IID_IReferenceClock, (LPVOID*)&m_pClock); m_rtStop = 0; //glewInit(); } CVirtualStream::~CVirtualStream() { LLOG("CVCamPin::~CVCamPin\n"); m_capture.Close(); if (m_packet != NULL) { delete m_packet; m_packet = NULL; } if (m_lastPacket != NULL) { delete m_lastPacket; m_lastPacket = NULL; } if (m_pClock != NULL) { m_pClock->Release(); m_pClock = NULL; } } STDMETHODIMP CVirtualStream::Notify(IBaseFilter * pSender, Quality q) { return E_FAIL; } // Notify // // GetMediaType // // Prefer 5 formats - 8, 16 (*2), 24 or 32 bits per pixel // // Prefered types should be ordered by quality, with zero as highest quality. // Therefore, iPosition = // 0 Return a 32bit mediatype // 1 Return a 24bit mediatype // 2 Return 16bit RGB565 // 3 Return a 16bit mediatype (rgb555) // 4 Return 8 bit palettised format // >4 Invalid // HRESULT CVirtualStream::GetMediaType(int iPosition, CMediaType *pmt) { LLOG("CVCamPin::GetMediaType:.%d\n", iPosition); CheckPointer(pmt, E_POINTER); CAutoLock cAutoLock(m_pFilter->pStateLock()); if (iPosition < 0) { return E_INVALIDARG; } // Have we run off the end of types? if (iPosition > 0) { return VFW_S_NO_MORE_ITEMS; } VIDEOINFO *pvi = (VIDEOINFO*)pmt->Format(); if (pvi == NULL || pmt->cbFormat != sizeof(VIDEOINFO)) { pvi = (VIDEOINFO *)pmt->AllocFormatBuffer(sizeof(VIDEOINFO)); if (NULL == pvi) { LERROR("CVCamPin::GetMediaType:AllocFormatBuffer == NULL\n"); return(E_OUTOFMEMORY); } // Initialize the VideoInfo structure before configuring its members ZeroMemory(pvi, sizeof(VIDEOINFO)); } else { LLOG("CVCamPin::GetMediaType:No Alloc\n"); } { // Return our 24bit format pvi->bmiHeader.biCompression = BI_RGB; pvi->bmiHeader.biBitCount = 24; } // Adjust the parameters common to all formats pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pvi->bmiHeader.biWidth = m_iImageWidth; pvi->bmiHeader.biHeight = m_iImageHeight; pvi->bmiHeader.biPlanes = 1; pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader); pvi->bmiHeader.biClrImportant = 0; SetRectEmpty(&(pvi->rcSource)); // we want the whole image area rendered. SetRectEmpty(&(pvi->rcTarget)); // no particular destination rectangle pvi->rcSource.right = m_iImageWidth; pvi->rcSource.bottom = abs(m_iImageHeight); pvi->AvgTimePerFrame = (1000000000 / 100) / 30; pvi->dwBitRate = m_iImageWidth*abs(m_iImageHeight) * 3 * 30; pmt->SetType(&MEDIATYPE_Video); pmt->SetFormatType(&FORMAT_VideoInfo); pmt->SetTemporalCompression(FALSE); pmt->bFixedSizeSamples = FALSE; // Work out the GUID for the subtype from the header info. const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader); pmt->SetSubtype(&SubTypeGUID); pmt->SetSampleSize(pvi->bmiHeader.biSizeImage); LLOG("CVCamPin::GetMediaType:S_OK\n"); return NOERROR; } // GetMediaType // // CheckMediaType // // We will accept 8, 16, 24 or 32 bit video formats, in any // image size that gives room to bounce. // Returns E_INVALIDARG if the mediatype is not acceptable // HRESULT CVirtualStream::CheckMediaType(const CMediaType *pMediaType) { LLOG("CVCamPin::CheckMediaType:.\n"); CheckPointer(pMediaType, E_POINTER); //CAutoLock cAutoLock(m_pFilter->pStateLock()); if ((*(pMediaType->Type()) != MEDIATYPE_Video) || // we only output video !(pMediaType->IsFixedSize())) // in fixed size samples { LERROR("CVCamPin::CheckMediaType: Error 1\n"); return E_INVALIDARG; } // Check for the subtypes we support const GUID *SubType = pMediaType->Subtype(); if (SubType == NULL) { LERROR("CVCamPin::CheckMediaType: Error 2\n"); return E_INVALIDARG; } if ((*SubType != MEDIASUBTYPE_RGB8) && (*SubType != MEDIASUBTYPE_RGB565) && (*SubType != MEDIASUBTYPE_RGB555) && (*SubType != MEDIASUBTYPE_RGB24) && (*SubType != MEDIASUBTYPE_RGB32)) { LERROR("CVCamPin::CheckMediaType: Error 3\n"); return E_INVALIDARG; } // Get the format area of the media type VIDEOINFO *pvi = (VIDEOINFO *)pMediaType->Format(); if (pvi == NULL) { LERROR("CVCamPin::CheckMediaType: Error 4\n"); return E_INVALIDARG; } // Check if the image width & height have changed if (pvi->bmiHeader.biWidth != m_iImageWidth || abs(pvi->bmiHeader.biHeight) != m_iImageHeight) { // If the image width/height is changed, fail CheckMediaType() to force // the renderer to resize the image. LERROR("CVCamPin::CheckMediaType: Error 5\n"); return E_INVALIDARG; } // Don't accept formats with negative height, which would cause the desktop // image to be displayed upside down. if (pvi->bmiHeader.biHeight < 0) { LERROR("CVCamPin::CheckMediaType: Error 6\n"); return E_INVALIDARG; } LLOG("CVCamPin::CheckMediaType:S_OK\n"); return S_OK; // This format is acceptable. } // CheckMediaType // // SetMediaType // // Called when a media type is agreed between filters // HRESULT CVirtualStream::SetMediaType(const CMediaType *pMediaType) { LLOG("CVCamPin::SetMediaType:.\n"); CAutoLock cAutoLock(m_pFilter->pStateLock()); // Pass the call up to my base class HRESULT hr = CSourceStream::SetMediaType(pMediaType); if (SUCCEEDED(hr)) { VIDEOINFO * pvi = (VIDEOINFO *)m_mt.Format(); if (pvi == NULL) { LERROR("CVCamPin::SetMediaType: Error 1\n"); return E_UNEXPECTED; } switch (pvi->bmiHeader.biBitCount) { //case 8: // 8-bit palettized //case 16: // RGB565, RGB555 case 24: // RGB24 //case 32: // RGB32 hr = S_OK; break; default:{ LLOG("CVCamPin::SetMediaType:%d\n", pvi->bmiHeader.biBitCount); // We should never agree any other media types ASSERT(FALSE); hr = E_INVALIDARG; break; } } } LLOG("CVCamPin::SetMediaType:%s (%X)\n", SUCCEEDED(hr) ? "S_OK" : "S_FAULE", hr); return hr; } // SetMediaType // // DecideBufferSize // // This will always be called after the format has been sucessfully // negotiated. So we have a look at m_mt to see what size image we agreed. // Then we can ask for buffers of the correct size to contain them. // HRESULT CVirtualStream::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties) { LLOG("CVCamPin::DecideBufferSize:.\n"); CheckPointer(pAlloc, E_POINTER); CheckPointer(pProperties, E_POINTER); CAutoLock cAutoLock(m_pFilter->pStateLock()); HRESULT hr = NOERROR; VIDEOINFO *pvi = (VIDEOINFO *)m_mt.Format(); ASSERT(pvi != NULL); pProperties->cBuffers = 1; pProperties->cbBuffer = pvi->bmiHeader.biSizeImage; ASSERT(pProperties->cbBuffer); // Ask the allocator to reserve us some sample memory. NOTE: the function // can succeed (return NOERROR) but still not have allocated the // memory that we requested, so we must check we got whatever we wanted. ALLOCATOR_PROPERTIES Actual = { 0 }; hr = pAlloc->SetProperties(pProperties, &Actual); if (FAILED(hr)) { LERROR("CVCamPin::DecideBufferSize: Error 1(%X)\n", hr); return hr; } // Is this allocator unsuitable? if (Actual.cbBuffer < pProperties->cbBuffer) { LERROR("CVCamPin::DecideBufferSize: Error 2(%d %d)\n", Actual.cbBuffer, pProperties->cbBuffer); return E_FAIL; } // Make sure that we have only 1 buffer (we erase the ball in the // old buffer to save having to zero a 200k+ buffer every time // we draw a frame) ASSERT(Actual.cBuffers == 1); LLOG("CVCamPin::DecideBufferSize:S_OK\n"); return NOERROR; } // DecideBufferSize // This is where we insert the DIB bits into the video stream. // FillBuffer is called once for every sample in the stream. HRESULT CVirtualStream::FillBuffer(IMediaSample *pSample) { CheckPointer(pSample, E_POINTER); CAutoLock cAutoLockShared(&m_cSharedState); BYTE *pData = NULL; long cbData; // Access the sample's data buffer pSample->GetPointer(&pData); cbData = pSample->GetSize(); REFERENCE_TIME rtStart = m_iFrameNumber * m_rtFrameLength; while (true) { m_pClock->GetTime(&rtStart); if (m_rtStop <= rtStart) { break; } else { Sleep(1); } } { ASSERT(pData != NULL); // Check that we're still using video ASSERT(m_mt.formattype == FORMAT_VideoInfo); VIDEOINFO *pVih = (VIDEOINFO*)m_mt.pbFormat; ASSERT(pVih != NULL); // Copy the DIB bits over into our filter's output buffer. // Since sample size may be larger than the image size, bound the copy size. EvoPacket * packet = NULL; { CAutoLock cAutoLockShared(&m_cSharedData); packet = m_packet; if (packet == NULL) { packet = m_lastPacket; } else { if (m_lastPacket != NULL) { PoolDelete(&m_lastPacket); } m_lastPacket = m_packet; m_packet = NULL; } } if (packet != NULL && packet->GetPacketSize() == cbData) { EvoAttributeMemory * buffer = (EvoAttributeMemory*)packet; memcpy(pData, buffer->GetData(), cbData); } else { if (m_nDeviceID == -1) { FillRainbowBar((char*)pData, cbData, pVih->bmiHeader.biWidth, abs(pVih->bmiHeader.biHeight)); } else { memset(pData, 0, cbData); } } } pSample->SetActualDataLength(cbData); // Set the timestamps that will govern playback frame rate. // If this file is getting written out as an AVI, // then you'll also need to configure the AVI Mux filter to // set the Average Time Per Frame for the AVI Header. // The current time is the sample's start. REFERENCE_TIME rtStop = rtStart + m_rtFrameLength; rtStop = rtStart + m_rtFrameLength; pSample->SetTime((REFERENCE_TIME *)&rtStart, (REFERENCE_TIME *)&rtStop); pSample->SetMediaTime((REFERENCE_TIME *)&rtStart, (REFERENCE_TIME *)&rtStop); m_rtStop = rtStop; m_iFrameNumber++; pSample->SetDiscontinuity(FALSE); pSample->SetPreroll(FALSE); // Set TRUE on every sample for uncompressed frames pSample->SetSyncPoint(TRUE); return S_OK; } ////////////////////////////////////////////////////////////////////////// // IAMStreamConfig ////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CVirtualStream::SetFormat(AM_MEDIA_TYPE *pmt) { LLOG("CVCamPin::SetFormat:.\n"); if (pmt == NULL) { LLOG("CVCamPin::SetFormat:E_POINTER\n"); return E_POINTER; } //CAutoLock cAutoLockShared(&m_cSharedState); DECLARE_PTR(VIDEOINFOHEADER, pvi, m_mt.pbFormat); m_mt = *pmt; IPin* pin = NULL; ConnectedTo(&pin); if (pin) { ASSERT(m_pFilter != NULL); IFilterGraph *pGraph = m_pFilter->GetFilterGraph(); ASSERT(pGraph != NULL); pGraph->Reconnect(this); } else { LERROR("CVCamPin::SetFormat: Error\n"); } LLOG("CVCamPin::SetFormat:S_OK\n"); return S_OK; } HRESULT STDMETHODCALLTYPE CVirtualStream::GetFormat(AM_MEDIA_TYPE **ppmt) { //CAutoLock cAutoLockShared(&m_cSharedState); if (ppmt != NULL) { *ppmt = CreateMediaType(&m_mt); } LLOG("CVCamPin::GetFormat:S_OK\n"); return S_OK; } HRESULT STDMETHODCALLTYPE CVirtualStream::GetNumberOfCapabilities(int *piCount, int *piSize) { LLOG("CVCamPin::GetNumberOfCapabilities:S_OK\n"); *piCount = 1; *piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS); return S_OK; } HRESULT STDMETHODCALLTYPE CVirtualStream::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC) { LLOG("CVCamPin::GetStreamCaps:.%d\n", iIndex); if (pmt == NULL) { LERROR("CVCamPin::GetStreamCaps:pmt == NULL\n"); return E_POINTER; } if (m_mt.majortype != MEDIATYPE_Video) { LERROR("CVCamPin::GetStreamCaps:m_mt.majortype != MEDIATYPE_Video\n"); return VFW_E_NOT_CONNECTED; } if (*pmt == NULL) { *pmt = CreateMediaType(&m_mt); } if (*pmt == NULL) { LERROR("CVCamPin::GetStreamCaps:*pmt == NULL\n"); return E_POINTER; } DECLARE_PTR(VIDEOINFO, pvi, (*pmt)->pbFormat); if (pvi == NULL) { LERROR("CVCamPin::GetStreamCaps:pvi == NULL %d (%d %d)\n", iIndex, m_mt.cbFormat, m_mt.lSampleSize); DeleteMediaType(*pmt); *pmt = NULL; return E_POINTER; } else { LLOG("CVCamPin::GetStreamCaps:%d (%d %d)\n", iIndex, m_mt.cbFormat, m_mt.lSampleSize); if (iIndex == 0) iIndex = 8; pvi->bmiHeader.biCompression = BI_RGB; pvi->bmiHeader.biBitCount = 24; pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pvi->bmiHeader.biWidth = m_iImageWidth; pvi->bmiHeader.biHeight = m_iImageHeight; pvi->bmiHeader.biPlanes = 1; pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader); pvi->bmiHeader.biClrImportant = 0; SetRectEmpty(&(pvi->rcSource)); // we want the whole image area rendered. SetRectEmpty(&(pvi->rcTarget)); // no particular destination rectangle pvi->rcSource.right = m_iImageWidth; pvi->rcSource.bottom = abs(m_iImageHeight); pvi->AvgTimePerFrame = (1000000000 / 100) / 30; pvi->dwBitRate = m_iImageWidth*abs(m_iImageHeight)*3*30; (*pmt)->majortype = MEDIATYPE_Video; (*pmt)->subtype = MEDIASUBTYPE_RGB24; (*pmt)->formattype = FORMAT_VideoInfo; (*pmt)->bTemporalCompression = FALSE; (*pmt)->bFixedSizeSamples= FALSE; (*pmt)->lSampleSize = pvi->bmiHeader.biSizeImage; (*pmt)->cbFormat = sizeof(VIDEOINFO); } if (pSCC == NULL) { LERROR("CVCamPin::GetStreamCaps:pSCC == NULL\n"); return E_POINTER; } else { DECLARE_PTR(VIDEO_STREAM_CONFIG_CAPS, pvscc, pSCC); pvscc->guid = FORMAT_VideoInfo; pvscc->VideoStandard = AnalogVideo_None; pvscc->InputSize.cx = 0; pvscc->InputSize.cy = 0; pvscc->MinCroppingSize.cx = m_iImageWidth; pvscc->MinCroppingSize.cy = m_iImageHeight; pvscc->MaxCroppingSize.cx = m_iImageWidth; pvscc->MaxCroppingSize.cy = m_iImageHeight; pvscc->CropGranularityX = m_iImageWidth; pvscc->CropGranularityY = m_iImageHeight; pvscc->CropAlignX = 0; pvscc->CropAlignY = 0; pvscc->MinOutputSize.cx = m_iImageWidth; pvscc->MinOutputSize.cy = m_iImageHeight; pvscc->MaxOutputSize.cx = m_iImageWidth; pvscc->MaxOutputSize.cy = m_iImageHeight; pvscc->OutputGranularityX = 0; pvscc->OutputGranularityY = 0; pvscc->StretchTapsX = 0; pvscc->StretchTapsY = 0; pvscc->ShrinkTapsX = 0; pvscc->ShrinkTapsY = 0; pvscc->MinFrameInterval = 33333; //30 fps pvscc->MaxFrameInterval = 33333;// 10000000; //0.1 fps pvscc->MinBitsPerSecond = (m_iImageWidth * m_iImageHeight * 3 * 8) * 30; pvscc->MaxBitsPerSecond = (m_iImageWidth * m_iImageHeight * 3 * 8) * 30; } LLOG("CVCamPin::GetStreamCaps:S_OK\n"); return S_OK; } ////////////////////////////////////////////////////////////////////////// // IKsPropertySet ////////////////////////////////////////////////////////////////////////// HRESULT CVirtualStream::Set(REFGUID guidPropSet, DWORD dwID, void *pInstanceData, DWORD cbInstanceData, void *pPropData, DWORD cbPropData) {// Set: Cannot set any properties. LLOG("CVCamPin::Set:S_OK\n"); return E_NOTIMPL; } // Get: Return the pin category (our only property). HRESULT CVirtualStream::Get(REFGUID guidPropSet, // Which property set. DWORD dwPropID, // Which property in that set. void *pInstanceData, // Instance data (ignore). DWORD cbInstanceData, // Size of the instance data (ignore). void *pPropData, // Buffer to receive the property data. DWORD cbPropData, // Size of the buffer. DWORD *pcbReturned // Return the size of the property. ) { LLOG("CVCamPin::Get:.\n"); if (guidPropSet != AMPROPSETID_Pin) return E_PROP_SET_UNSUPPORTED; if (dwPropID != AMPROPERTY_PIN_CATEGORY) return E_PROP_ID_UNSUPPORTED; if (pPropData == NULL && pcbReturned == NULL) return E_POINTER; if (pcbReturned) *pcbReturned = sizeof(GUID); if (pPropData == NULL) return S_OK; // Caller just wants to know the size. if (cbPropData < sizeof(GUID)) return E_UNEXPECTED;// The buffer is too small. *(GUID *)pPropData = PIN_CATEGORY_CAPTURE; LLOG("CVCamPin::Get:OK\n"); return S_OK; } // QuerySupported: Query whether the pin supports the specified property. HRESULT CVirtualStream::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport) { if (guidPropSet != AMPROPSETID_Pin) return E_PROP_SET_UNSUPPORTED; if (dwPropID != AMPROPERTY_PIN_CATEGORY) return E_PROP_ID_UNSUPPORTED; // We support getting this property, but not setting it. if (pTypeSupport) *pTypeSupport = KSPROPERTY_SUPPORT_GET; return S_OK; } int index = 0; void DumpBMP(BITMAPINFOHEADER bmiHeader, BYTE *pBuffer, long lBufferSize) { BITMAPFILEHEADER header = { 0 }; header.bfType = 0x4D42; header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); header.bfSize = header.bfOffBits + lBufferSize; char buffer[1024]; sprintf_s(buffer,1024, "E:/tmp/%d.bmp", index++); FILE * file = NULL; fopen_s(&file,buffer, "wb+"); fwrite(&header, sizeof(BITMAPFILEHEADER), 1, file); fwrite(&bmiHeader, sizeof(BITMAPINFOHEADER), 1, file); fwrite(pBuffer, lBufferSize, 1, file); fclose(file); } void CVirtualStream::VideoFrameData(double dblSampleTime, BYTE * pBuffer, long lBufferSize) { EvoAttributeMemory * data = (EvoAttributeMemory*)PoolNew(lBufferSize); if (data != NULL) { uint8_t * buffer = data->GetData(); memcpy(buffer, pBuffer, lBufferSize); data->SetPTS(dblSampleTime); VIDEOINFO *pVih = (VIDEOINFO*)m_mt.pbFormat; ASSERT(pVih != NULL); //测试,直接输出BMP文件 DumpBMP(pVih->bmiHeader,pBuffer,lBufferSize); CAutoLock cAutoLockShared(&m_cSharedData); EvoPacket * tmp = m_packet; m_packet = data; PoolDelete(&tmp); } } EvoPacket *CVirtualStream::PoolNew(uint32_t dataSize) { PacketPool * pool = GetPool(); EvoPacket * packet = NULL; if (pool != NULL) { packet = pool->GetPacket(EvoAttributeMemory::GetTag(dataSize), EvoPacket::TypeEnum::TYPE_ATTRIBUTE_MEMORY, dataSize); if (packet != NULL) { packet->Validate(); } } if (packet == NULL) { return EvoPacketAllocator::CreateNew(dataSize, EvoPacket::TypeEnum::TYPE_ATTRIBUTE_MEMORY); } return packet; } void CVirtualStream::PoolDelete(EvoPacket **packet) { PacketPool * pool = PacketPool::GetInstance(PACKET_LIST_MAX_SIZE); if (packet != NULL) { if (*packet == NULL) return; if (pool != NULL) { pool->PutPacket(packet); } else { Delete(packet); } } } void CVirtualStream::Delete(EvoPacket **packet) { if (packet == NULL) return; if (*packet == NULL) return; delete *packet; *packet = NULL; } PacketPool *CVirtualStream::GetPool() { return &pool; } void CVirtualStream::FillRainbowBar(char * buffer, int size, int width, int height) { if (size != width*height * 3) return; //RGB int ColorTable[] = {0xFFFFFF,0xFFFF01,0x01FFFF,0x00FF01,0xFF00FF,0x0000FE,0x000000}; int ColorWidth[] = { 0,0,0,0,0,0,0 }; int space = width / 7; int border = width % 7; ColorWidth[0] = ColorWidth[1] = ColorWidth[2] = ColorWidth[3] = ColorWidth[4] = ColorWidth[5] = ColorWidth[6] = space; switch (border) { case 1: ColorWidth[0] += 1; break; case 2: ColorWidth[0] += 1; ColorWidth[6] += 1; break; case 3: ColorWidth[0] += 1; ColorWidth[3] += 1; ColorWidth[6] += 1; break; case 4: ColorWidth[0] += 1; ColorWidth[2] += 1; ColorWidth[4] += 1; ColorWidth[6] += 1; break; case 5: ColorWidth[1] += 1; ColorWidth[2] += 1; ColorWidth[3] += 1; ColorWidth[4] += 1; ColorWidth[5] += 1; break; case 6: ColorWidth[0] += 1; ColorWidth[1] += 1; ColorWidth[2] += 1; ColorWidth[4] += 1; ColorWidth[5] += 1; ColorWidth[6] += 1; break; } int index = 0; int index_width = 0; char r = 0, g = 0, b = 0; int color = ColorTable[index]; r = (char)(color >> 16); g = (char)((color >> 8) & 0xFF); b = (char)(color & 0xFF); int ci = ColorWidth[index]; for (int i = 0; i < width; i++) { buffer[i * 3] = r; buffer[i * 3 + 1] = g; buffer[i * 3 + 2] = b; if (index_width > ci) { index++; index_width = 0; if (index > 6) index = 6; int color = ColorTable[index]; r = (char)(color >> 16); g = (char)((color >> 8) & 0xFF); b = (char)(color & 0xFF); ci = ColorWidth[index]; } else { index_width++; } } for (int i = 1; i < height; i++) { memcpy(&buffer[i*width*3], buffer, width * 3); } }
CVirtualStream继承的IAMStreamConfig是摄像头分辨率修改接口,IKsPropertySet用于提供扩展接口支持
CVideoFrameHandler用于采集接口回调数据.
//缓冲器
PacketPool pool;
//当前数据
EvoPacket *m_packet;
EvoPacket *m_lastPacket;
这几个类是公司内部模块,暂不能上传,只是看效果的话这几个模块都可以直接去掉.
CCaptureVideo m_capture;是摄像头数据采集模块
数据采集模块代码:
#pragma once //http://blog.csdn.net/gaoguide/article/details/47867783 #ifndef POINTER_64 #define POINTER_64 __ptr64 #endif #include <dshow.h> #include <qedit.h> #include <d3d9.h> #include <streams.h> #include <initguid.h> #include <vector> #include <string> #include "SampleGrabberCB.h" #ifndef SAFE_RELEASE #define SAFE_RELEASE( x ) \ if ( NULL != x ) \ { \ x->Release( ); \ x = NULL; \ } #endif class CCaptureVideo { public: //打开视频采集 HRESULT Open(int iDeviceID, bool ShowVideo = false); //开始采集 HRESULT Play(); //关闭采集 HRESULT Close(); CCaptureVideo(); virtual ~CCaptureVideo(); //获取数据回调对象 CSampleGrabberCB *GetSampleGrabberCB(); //设置并开启数据处理模块 void GrabVideoFrames(BOOL bGrabVideoFrames, CVideoFrameHandler * frame_handler); //枚举视频设备 int EnumDevices(std::vector<std::string> &Devices); protected: IGraphBuilder * m_pGB; ICaptureGraphBuilder2* m_pCapture; IBaseFilter* m_pBF; IMediaControl* m_pMC; IVideoWindow* m_pVW; IBaseFilter* m_pGrabberFilter; ISampleGrabber* m_pGrabber; CSampleGrabberCB mCB; protected: //释放视频类型 void FreeMediaType(AM_MEDIA_TYPE& mt); //绑定采集设备 bool BindFilter(int deviceId, IBaseFilter **pFilter); //初始化 HRESULT InitCaptureGraphBuilder(); };
#include "CCaptureVideo.h" #include <atlbase.h> #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif #pragma comment(lib,"Strmiids.lib") #define LLOG #define LERROR ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCaptureVideo::CCaptureVideo() { //COM Library Intialization if (FAILED(CoInitialize(NULL))) /*, COINIT_APARTMENTTHREADED)))*/ { LERROR("CCaptureVideo CoInitialize Failed!\r\n"); return; } m_pVW = NULL; m_pMC = NULL; m_pGB = NULL; m_pBF = NULL; m_pGrabber = NULL; m_pGrabberFilter = NULL; m_pCapture = NULL; } CCaptureVideo::~CCaptureVideo() { if (m_pMC)m_pMC->StopWhenReady(); if (m_pVW) { m_pVW->put_Visible(OAFALSE); m_pVW->put_Owner(NULL); } SAFE_RELEASE(m_pMC); SAFE_RELEASE(m_pVW); SAFE_RELEASE(m_pGB); SAFE_RELEASE(m_pBF); SAFE_RELEASE(m_pGrabber); SAFE_RELEASE(m_pGrabberFilter); SAFE_RELEASE(m_pCapture); CoUninitialize(); } CSampleGrabberCB *CCaptureVideo::GetSampleGrabberCB() { return &mCB; } int CCaptureVideo::EnumDevices(std::vector<std::string> &Devices) { int id = 0; //枚举视频扑捉设备 ICreateDevEnum *pCreateDevEnum; HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum); if (hr != NOERROR)return -1; CComPtr<IEnumMoniker> 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]; id++; #ifdef _UNICODE WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, str, 2048, NULL, NULL); #else strncpy(str,2048,var.bstrVal); #endif Devices.push_back(str); SysFreeString(var.bstrVal); } pBag->Release(); } pM->Release(); } return id; } HRESULT CCaptureVideo::Close() { // Stop media playback if (m_pMC)m_pMC->StopWhenReady(); if (m_pVW) { m_pVW->put_Visible(OAFALSE); m_pVW->put_Owner(NULL); } SAFE_RELEASE(m_pMC); SAFE_RELEASE(m_pVW); SAFE_RELEASE(m_pGB); SAFE_RELEASE(m_pBF); SAFE_RELEASE(m_pGrabber); SAFE_RELEASE(m_pGrabberFilter); SAFE_RELEASE(m_pCapture); return S_OK; } HRESULT CCaptureVideo::Open(int iDeviceID,bool ShowVideo) { HRESULT hr; hr = InitCaptureGraphBuilder(); if (FAILED(hr)) { LERROR("Failed to get video interfaces!"); return hr; } // Bind Device Filter. We know the device because the id was passed in 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_IBaseFilter, (void**)&m_pGrabberFilter); if (FAILED(hr)) { LERROR("Fail to create SampleGrabber, maybe qedit.dll is not registered?"); return hr; } m_pGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&m_pGrabber); //设置视频格式 AM_MEDIA_TYPE mt; ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE)); mt.majortype = MEDIATYPE_Video; mt.subtype = MEDIASUBTYPE_RGB24; // MEDIASUBTYPE_RGB24 ; mt.formattype = FORMAT_VideoInfo; hr = m_pGrabber->SetMediaType(&mt); if (FAILED(hr)) { LERROR("Fail to set media type!"); return hr; } hr = m_pGB->AddFilter(m_pGrabberFilter, L"Grabber"); if (FAILED(hr)) { LERROR("Fail to put sample grabber in graph"); return hr; } IBaseFilter *pNull = NULL; if (!ShowVideo) { hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pNull); if (FAILED(hr)) { LERROR("Fail to create NullRenderer."); return hr; } hr = m_pGB->AddFilter(pNull, L"NullRender"); if (FAILED(hr)) { LERROR("Fail to put NullRender in graph"); return hr; } } // try to render preview/capture pin hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pBF, m_pGrabberFilter, pNull); if (FAILED(hr)) hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pBF, m_pGrabberFilter, pNull); if (FAILED(hr)) { LERROR("Can’t build the graph"); return hr; } hr = m_pGrabber->GetConnectedMediaType(&mt); if (FAILED(hr)) { LERROR("Failt to read the connected media type"); return hr; } if (mt.subtype != MEDIASUBTYPE_RGB24 || mt.majortype != MEDIATYPE_Video) { LERROR("Failt to read the connected media type"); return hr; } VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*)mt.pbFormat; mCB.lWidth = vih->bmiHeader.biWidth; mCB.lHeight = vih->bmiHeader.biHeight; FreeMediaType(mt); mCB.bGrabVideo = FALSE; mCB.frame_handler = NULL; hr = m_pGrabber->SetBufferSamples(FALSE); hr = m_pGrabber->SetOneShot(FALSE); hr = m_pGrabber->SetCallback(&mCB, 1); return S_OK; } HRESULT CCaptureVideo::Play() { if (m_pMC == NULL) return S_FALSE; HRESULT hr = m_pMC->Run();//开始视频捕捉 if (FAILED(hr)) { LERROR("Couldn’t run the graph!"); return hr; } return S_OK; } bool CCaptureVideo::BindFilter(int deviceId, IBaseFilter **pFilter) { if (deviceId < 0) return false; // enumerate all video capture devices CComPtr<ICreateDevEnum> pCreateDevEnum; HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum); if (hr != NOERROR) { return false; } CComPtr<IEnumMoniker> 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; } 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; hr = m_pGB->QueryInterface(IID_IVideoWindow, (LPVOID *)&m_pVW); if (FAILED(hr))return hr; return hr; } 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; } } void CCaptureVideo::GrabVideoFrames(BOOL bGrabVideoFrames, CVideoFrameHandler * frame_handler) { mCB.frame_handler = frame_handler; mCB.bGrabVideo = bGrabVideoFrames; }
#pragma once #ifndef POINTER_64 #define POINTER_64 __ptr64 #endif #include <qedit.h> //视频数据回调 class CVideoFrameHandler { public: virtual void VideoFrameData(double dblSampleTime, BYTE * pBuffer, long lBufferSize) = 0; }; //样本数据采集器 class CSampleGrabberCB : public ISampleGrabberCB { public: long lWidth; long lHeight; CVideoFrameHandler * frame_handler; BOOL bGrabVideo; public: CSampleGrabberCB(); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); //数据采集回调 STDMETHODIMP SampleCB(double SampleTime, IMediaSample * pSample); STDMETHODIMP BufferCB(double dblSampleTime, BYTE * pBuffer, long lBufferSize); };
#include "SampleGrabberCB.h" CSampleGrabberCB::CSampleGrabberCB() { lWidth = 0; lHeight = 0; bGrabVideo = FALSE; frame_handler = NULL; } STDMETHODIMP_(ULONG) CSampleGrabberCB::AddRef() { return 2; } STDMETHODIMP_(ULONG) CSampleGrabberCB::Release() { return 1; } STDMETHODIMP CSampleGrabberCB::QueryInterface(REFIID riid, void ** ppv) { if (riid == IID_ISampleGrabberCB || riid == IID_IUnknown) { *ppv = (void *) static_cast<ISampleGrabberCB*>(this); return NOERROR; } return E_NOINTERFACE; } STDMETHODIMP CSampleGrabberCB::SampleCB(double SampleTime, IMediaSample * pSample) { return 0; } STDMETHODIMP CSampleGrabberCB::BufferCB(double dblSampleTime, BYTE * pBuffer, long lBufferSize) { if (!pBuffer) return E_POINTER; if (bGrabVideo && frame_handler) frame_handler->VideoFrameData(dblSampleTime, pBuffer, lBufferSize); return 0; }
相关文章推荐
- directshow 虚拟摄像头 实例 代码解读
- directshow 虚拟摄像头 实例 代码解读
- zz: Directshow 虚拟摄像头实现
- directshow 64位 虚拟摄像头笔记
- directshow的中文资料之控制视频回放窗口
- 使用DirectShow驱动摄像头
- DirectShow编程(1)- DirectShow介绍
- directshow入门级的好文章,相当不错
- 声卡输入端子在DirectShow中的自动选择
- Directshow中的视频捕捉
- 关于安装 DirectX SDk Dec 2005 后无法编译DirectShow应用程序的问题
- directshow播放mpeg
- 瑞风虚拟摄像头1.40版 Build 0504发布!
- 研究directshow的blog
- 基于DirectShow的MPEG-4视频传输系统的研究与实现
- DirectShow SDK笔记【关于DirectShow(2)】
- DirectShow系统初级指南
- Directshow开发的一些基本概念和技巧
- directshow摄像头录像代码
- DirectShow快速入门之参考时钟(zz)