#include #include #include #include "frameop.h" #include #include #include "..\nac\utils.h" #include "vidinout.h" #include "vcmstrm.h" #ifdef DEBUG extern "C" BOOL g_framedebug = TRUE; #endif // Base class methods STDMETHODIMP_(ULONG) CFrameOp::AddRef( void ) { FX_ENTRY("CFrameOp::AddRef"); DEBUGMSG(ZONE_NMCAP_REFCOUNT,("%s: refcnt+(0x%08lX [CFrameOp])=%d\r\n", _fx_, this, m_cRef+1)); return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CFrameOp::Release( void ) { LONG res; FX_ENTRY("CFrameOp::Release"); DEBUGMSG(ZONE_NMCAP_REFCOUNT,("%s: refcnt-(0x%08lX [CFrameOp])=%d\r\n", _fx_, this, m_cRef-1)); res = InterlockedDecrement(&m_cRef); if (res == 0) { if (m_pool) { m_pool->Release(); } if (m_next) m_next->Release(); DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: deleting (0x%08lX [CFrameOp])\r\n", _fx_, this)); delete this; } return res; } // CCaptureFrame methods CCaptureFrame::~CCaptureFrame( ) { if (m_hbuf1) FreeFrameBuffer(m_hcapdev, m_hbuf1); if (m_hbuf2) FreeFrameBuffer(m_hcapdev, m_hbuf2); } STDMETHODIMP CCaptureFrame::DoOp( IBitmapSurface** ppbs ) { HFRAMEBUF hbuf; BYTE* pBits; m_pool->GetBuffer(ppbs, &hbuf); if (*ppbs) { pBits = CaptureFrame(m_hcapdev, hbuf); return NO_ERROR; } return E_OUTOFMEMORY; } BOOL CCaptureFrame::InitCapture( HCAPDEV hcapdev, LPBITMAPINFOHEADER lpbmh ) { FX_ENTRY("CCaptureFrame::InitCapture"); if ((m_hbuf1 = AllocFrameBuffer(hcapdev)) && (m_hbuf2 = AllocFrameBuffer(hcapdev))) { if ((m_pool = new CVidPool)) { m_pool->AddRef(); if (m_pool->InitPool(0, lpbmh) == NO_ERROR) { m_pool->AddExternalBuffer(GetFrameBufferPtr(hcapdev, m_hbuf1), (void*)m_hbuf1); m_pool->AddExternalBuffer(GetFrameBufferPtr(hcapdev, m_hbuf2), (void*)m_hbuf2); m_hcapdev = hcapdev; DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: init capture (0x%08lX [CCaptureFrame])\r\n", _fx_, this)); return TRUE; } else { ERRORMESSAGE(("%s: Failed to init capture pool", _fx_)); m_pool->Release(); } } else { ERRORMESSAGE(("%s: Failed to alloc capture pool", _fx_)); } FreeFrameBuffer(hcapdev, m_hbuf2); } else { ERRORMESSAGE(("%s: Failed to allocate frame buffer", _fx_)); } if (m_hbuf1) FreeFrameBuffer(hcapdev, m_hbuf1); return FALSE; } // CStreamCaptureFrame methods CStreamCaptureFrame::~CStreamCaptureFrame( ) { StopStreaming(m_hcapdev); UninitializeStreaming(m_hcapdev); } STDMETHODIMP CStreamCaptureFrame::DoOp( IBitmapSurface** ppbs ) { long pitch; CAPFRAMEINFO cfi; CBitmap *pcb; FX_ENTRY ("CStreamCaptureFrame::DoOp") m_pool->GetBuffer(&pcb, NULL); if (pcb) { if (pcb->m_bits) { PutBufferIntoStream(m_hcapdev, (BYTE*)pcb->m_bits); pcb->m_bits = NULL; } GetNextReadyBuffer(m_hcapdev, &cfi); if (pcb->m_bits = (LPBYTE)cfi.lpData) { *ppbs = (IBitmapSurface*)pcb; return NO_ERROR; } DEBUGMSG(ZONE_NMCAP_STREAMING,("%s: Failed to get buffer from DCAP\r\n", _fx_)); pcb->Release(); } *ppbs = NULL; return E_OUTOFMEMORY; } void GiveBufferToDriver (CBitmap *pBitmap, DWORD_PTR refdata) { if (pBitmap->m_bits && refdata) { PutBufferIntoStream((HCAPDEV)refdata, (BYTE*)pBitmap->m_bits); pBitmap->m_bits = NULL; } } BOOL CStreamCaptureFrame::InitCapture( HCAPDEV hcapdev, LPBITMAPINFOHEADER lpbmh ) { CAPSTREAM cs; CAPFRAMEINFO cfi; FX_ENTRY("CStreamCaptureFrame::InitCapture"); // Initialize streaming cs.dwSize = sizeof (CAPSTREAM); cs.nFPSx100 = 30 * 100; cs.ncCapBuffers = 5; if (InitializeStreaming(hcapdev, &cs, 0)) { if (StartStreaming(hcapdev)) { if (WaitForSingleObject(cs.hevWait, 5000) != WAIT_TIMEOUT) { if ((m_pool = new CVidPool)) { m_pool->AddRef(); if (m_pool->InitPool(0, lpbmh) == NO_ERROR) { m_pool->m_pAddingToFree = &GiveBufferToDriver; m_pool->m_refdata = (DWORD_PTR)hcapdev; m_pool->AddExternalBuffer(NULL, (void*)1); m_pool->AddExternalBuffer(NULL, (void*)2); m_hcapdev = hcapdev; DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: init stream capture (0x%08lX [CStreamCaptureFrame])\r\n", _fx_, this)); return TRUE; } else { ERRORMESSAGE(("%s: Failed to init capture pool", _fx_)); m_pool->Release(); } } else { ERRORMESSAGE(("%s: Failed to alloc capture pool", _fx_)); } } else { ERRORMESSAGE(("%s: Error no frame events received", _fx_)); } } else { ERRORMESSAGE(("%s: Error starting streaming", _fx_)); } UninitializeStreaming(hcapdev); } else { ERRORMESSAGE(("%s: Error initializing streaming", _fx_)); } return FALSE; } // CICMcvtFrame methods CICMcvtFrame::~CICMcvtFrame( ) { if (m_hic) { ICDecompressEnd(m_hic); ICClose(m_hic); } if (m_inlpbmh) LocalFree((HANDLE)m_inlpbmh); if (m_outlpbmh) LocalFree((HANDLE)m_outlpbmh); } STDMETHODIMP CICMcvtFrame::DoOp( IBitmapSurface** ppbs ) { BYTE* pBits; BYTE* pCvtBits; long pitch; IBitmapSurface *pBS; m_pool->GetBuffer(&pBS, NULL); if (pBS) { (*ppbs)->LockBits(NULL, 0, (void**)&pBits, &pitch); pBS->LockBits(NULL, 0, (void**)&pCvtBits, &pitch); ICDecompress(m_hic, 0, m_inlpbmh, pBits, m_outlpbmh, pCvtBits); (*ppbs)->UnlockBits(NULL, pBits); pBS->UnlockBits(NULL, pCvtBits); (*ppbs)->Release(); // done with the capture buffer *ppbs = pBS; return NO_ERROR; } return E_OUTOFMEMORY; } BOOL CICMcvtFrame::InitCvt( LPBITMAPINFOHEADER lpbmh, DWORD bmhLen, LPBITMAPINFOHEADER *plpbmhdsp ) { DWORD dwLen; HIC hic; FX_ENTRY("CICMcvtFrame::InitCvt"); *plpbmhdsp = lpbmh; if (lpbmh->biCompression != BI_RGB) { *plpbmhdsp = NULL; // make internal copy of input BITMAPINFOHEADER m_inlpbmh = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, bmhLen); if (!m_inlpbmh) { ERRORMESSAGE(("%s: No memory for display bitmapinfoheader", _fx_)); return FALSE; } CopyMemory(m_inlpbmh, lpbmh, bmhLen); // alloc space for display BITMAPINFOHEADER dwLen = sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD); m_outlpbmh = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, dwLen); if (!m_outlpbmh) { LocalFree((HANDLE)m_inlpbmh); ERRORMESSAGE(("%s: No memory for display bitmapinfoheader", _fx_)); return FALSE; } // First attempt to find a codec to convert to RGB24 hic = ICGetDisplayFormat(NULL, lpbmh, m_outlpbmh, 24, 0, 0); if (!hic) { // nothing available to convert to RGB24, so see what we can get hic = ICGetDisplayFormat(NULL, lpbmh, m_outlpbmh, 0, 0, 0); } if (hic) { if (m_outlpbmh->biCompression == BI_RGB) { // we got a codec that can convert to RGB *plpbmhdsp = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, dwLen); if (*plpbmhdsp) { CopyMemory(*plpbmhdsp, m_outlpbmh, dwLen); if ((m_pool = new CVidPool)) { m_pool->AddRef(); if (m_pool->InitPool(2, m_outlpbmh) == NO_ERROR) { m_hic = hic; ICDecompressBegin(m_hic, m_inlpbmh, m_outlpbmh); DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: init ICM cvt (0x%08lX [CICMcvtFrame])\r\n", _fx_, this)); return TRUE; } else { ERRORMESSAGE(("%s: Failed to init codec pool", _fx_)); m_pool->Release(); } } else { ERRORMESSAGE(("%s: Failed to alloc codec pool", _fx_)); } LocalFree((HANDLE)*plpbmhdsp); } else { ERRORMESSAGE(("%s: Failed to init codec pool", _fx_)); } } ICClose(hic); // close the opened codec } else { ERRORMESSAGE(("%s: No available codecs to decode format", _fx_)); } // free allocate BITMAPINFOHEADER memory LocalFree((HANDLE)m_inlpbmh); m_inlpbmh = NULL; LocalFree((HANDLE)m_outlpbmh); m_outlpbmh = NULL; } return FALSE; } //CFilterChain methods CFilterChain::~CFilterChain( ) { if (m_head) m_head->Release(); } STDMETHODIMP CFilterChain::DoOp( IBitmapSurface** ppbs ) { CFilterFrame *cfo; HRESULT hres; cfo = m_head; while (cfo) { if (cfo->m_enabled) { if ((hres = cfo->DoOp(ppbs)) != NOERROR) { return hres; } } cfo = (CFilterFrame*)cfo->m_next; } return NOERROR; } //CFilterFrame methods CFilterFrame::~CFilterFrame( ) { if (m_effect) m_effect->Release(); } STDMETHODIMP CFilterFrame::DoOp( IBitmapSurface** ppbs ) { HRESULT hres; IBitmapSurface* pBS; if (m_inplace) { return m_effect->DoEffect(*ppbs, NULL, NULL, NULL); } else { m_pool->GetBuffer(&pBS, NULL); if (pBS) { hres = m_effect->DoEffect(*ppbs, pBS, NULL, NULL); (*ppbs)->Release(); *ppbs = pBS; return hres; } return E_OUTOFMEMORY; } } BOOL CFilterFrame::InitFilter( IBitmapEffect *effect, LPBITMAPINFOHEADER lpbmhIn, CVidPool *pool ) { DWORD dwFlags; FX_ENTRY("CFilterFrame::InitFilter"); m_effect = effect; if (effect->GetMiscStatusBits(&dwFlags) == NO_ERROR) { m_inplace = (dwFlags & BITMAP_EFFECT_INPLACE); } else m_inplace = TRUE; // assumption! if (!m_inplace) { // we'll need a pool if (!pool || !(pool->Growable())) return FALSE; m_pool = pool; m_pool->AddRef(); } DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: init filter (0x%08lX [CFilterFrame])\r\n", _fx_, this)); return TRUE; } //CConvertFrame internal routines //CConvertFrame methods CConvertFrame::~CConvertFrame() { if (m_refdata) LocalFree((HANDLE)m_refdata); } STDMETHODIMP CConvertFrame::DoOp( IBitmapSurface** ppbs ) { IBitmapSurface* pBS; if (m_convert) { m_pool->GetBuffer(&pBS, NULL); if (pBS) { if (m_convert(*ppbs, pBS, m_refdata)) { (*ppbs)->Release(); *ppbs = pBS; return NO_ERROR; } else { pBS->Release(); return E_FAIL; } } else return E_OUTOFMEMORY; } return E_UNEXPECTED; } BOOL CConvertFrame::InitConverter( LPBITMAPINFOHEADER lpbmh, FRAMECONVERTPROC *convertproc, LPVOID refdata ) { if (convertproc) { if ((m_pool = new CVidPool)) { m_pool->AddRef(); if (m_pool->InitPool(2, lpbmh) == NO_ERROR) { m_convert = convertproc; m_refdata = refdata; return TRUE; } m_pool->Release(); m_pool = NULL; } } return FALSE; }