#include #include #include #include #include #include "ibitmap.h" #include "ividpool.h" #include "vidpool.h" #include #include #include "..\nac\utils.h" #ifdef DEBUG extern "C" BOOL g_pooldebug = TRUE; #endif STDMETHODIMP CBitmap::QueryInterface( REFIID riid, LPVOID * ppvObj ) { if (riid == IID_IUnknown || riid == IID_IBitmapSurface) *ppvObj = (IBitmapSurface*)this; else { *ppvObj = 0; return E_NOINTERFACE; } ((IUnknown*)*ppvObj)->AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CBitmap::AddRef( void ) { FX_ENTRY("CBitmap::AddRef"); DEBUGMSG(ZONE_NMCAP_REFCOUNT,("%s: refcnt+(0x%08lX [CBitmap])=%d\r\n", _fx_, this, m_cRef+1)); return InterlockedIncrement(&m_cRef)+1; // make sure that we return something > 0 } STDMETHODIMP_(ULONG) CBitmap::Release( void ) { LONG res; FX_ENTRY("CBitmap::Release"); DEBUGMSG(ZONE_NMCAP_REFCOUNT,("%s: refcnt-(0x%08lX [CBitmap])=%d\r\n", _fx_, this, m_cRef-1)); res = InterlockedDecrement(&m_cRef); if (res == 0) { if (m_factory) { m_factory->AddToFreeList(this); } else { if (!m_ext) LocalFree((HANDLE)m_bits); DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: released (0x%08lX [CBitmap]) from vidpool (0x%08lX [m_factory])\r\n", _fx_, this, m_factory)); DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: deleting (0x%08lX [CBitmap])\r\n", _fx_, this)); delete this; } } return res; } STDMETHODIMP CBitmap::Clone( IBitmapSurface** ppBitmapSurface ) { return E_NOTIMPL; } STDMETHODIMP CBitmap::GetFormat( BFID* pBFID ) { *pBFID = *(m_factory->GetFormat()); return NOERROR; } STDMETHODIMP CBitmap::GetFactory( IBitmapSurfaceFactory** ppBitmapSurfaceFactory ) { *ppBitmapSurfaceFactory = (IBitmapSurfaceFactory*)m_factory; m_factory->AddRef(); return NOERROR; } STDMETHODIMP CBitmap::GetSize( long* pWidth, long* pHeight ) { *pWidth = m_factory->GetWidth(); *pHeight = m_factory->GetHeight(); return NOERROR; } STDMETHODIMP CBitmap::LockBits( RECT* prcBounds, DWORD dwLockFlags, void** ppBits, long* pPitch ) { if (!prcBounds) { *ppBits = m_bits; *pPitch = m_pitch; m_lockcount++; return NO_ERROR; } return E_NOTIMPL; } STDMETHODIMP CBitmap::UnlockBits( RECT* prcBounds, void* pBits ) { if (!prcBounds && pBits == m_bits) { m_lockcount--; return NO_ERROR; } return E_NOTIMPL; } CVidPool::CVidPool(void) { m_cRef = 0; m_growable = FALSE; m_nbufs = 0; m_free = NULL; m_pitch = 0; ZeroMemory(&m_format, sizeof(BFID)); InitializeCriticalSection(&m_cs); m_pAddingToFree = NULL; } STDMETHODIMP CVidPool::QueryInterface( REFIID riid, LPVOID * ppvObj ) { if (riid == IID_IUnknown || riid == IID_IBitmapSurfaceFactory) *ppvObj = (IBitmapSurfaceFactory*)this; else { *ppvObj = 0; return E_NOINTERFACE; } ((IUnknown*)*ppvObj)->AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CVidPool::AddRef( void ) { FX_ENTRY("CVidPool::AddRef"); DEBUGMSG(ZONE_NMCAP_REFCOUNT,("%s: refcnt+(0x%08lX [CVidPool])=%d\r\n", _fx_, this, m_cRef+1)); return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CVidPool::Release( void ) { CBitmap* pbs; FX_ENTRY("CVidPool::Release"); DEBUGMSG(ZONE_NMCAP_REFCOUNT,("%s: refcnt-(0x%08lX [CVidPool])=%d\r\n", _fx_, this, m_cRef-1)); if (InterlockedDecrement(&m_cRef) == 0) { DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: freeing (0x%08lX [CVidPool])\r\n", _fx_, this)); EnterCriticalSection(&m_cs); while (m_free) { pbs = m_free->m_next; m_free->AddRef(); // ref the buffer so that release will cause a delete m_free->Release(); // this will cause the buffer to be deleted m_free = pbs; #ifdef DEBUG m_nbufs--; #endif } LeaveCriticalSection(&m_cs); LocalFree((HANDLE)m_pbmh); DeleteCriticalSection(&m_cs); // Buffers not all released ASSERT(!m_nbufs); delete this; return 0; } return m_cRef; } STDMETHODIMP CVidPool::CreateBitmapSurface( long width, long height, BFID* pBFID, DWORD dwHintFlags, IBitmapSurface** ppBitmapSurface ) { return E_NOTIMPL; } STDMETHODIMP CVidPool::GetSupportedFormatsCount( long* pcFormats ) { return E_NOTIMPL; } STDMETHODIMP CVidPool::GetSupportedFormats( long cFormats, BFID* pBFIDs ) { return E_NOTIMPL; } STDMETHODIMP CVidPool::InitPool( int nBuffers, LPBITMAPINFOHEADER lpcap ) { CBitmap* pbs; void *pbuf; FX_ENTRY("CVidPool::InitPool"); if (m_pbmh = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, lpcap->biSize)) { CopyMemory(m_pbmh, lpcap, lpcap->biSize); if (lpcap->biCompression == BI_RGB) { m_pitch = lpcap->biWidth*lpcap->biBitCount/8; switch (lpcap->biBitCount) { case 1: m_format = (BFID*)&BFID_MONOCHROME; break; case 4: m_format = (BFID*)&BFID_RGB_4; break; case 8: m_format = (BFID*)&BFID_RGB_8; break; case 16: m_format = (BFID*)&BFID_RGB_555; break; case 24: m_format = (BFID*)&BFID_RGB_24; break; case 32: m_format = (BFID*)&BFID_RGB_32; } } else { m_format = (BFID*)&BFID_PRIVATEDIB; m_pitch = 1; } for (m_nbufs = 0; m_nbufs < nBuffers; m_nbufs++) { if (pbuf = LocalAlloc(LMEM_FIXED, lpcap->biSizeImage)) { if (pbs = new CBitmap) { // pbs->AddRef(); - don't AddRef, we want inpool objects to be 0 based pbs->m_bits = (LPBYTE)pbuf; pbs->m_pitch = m_pitch; EnterCriticalSection(&m_cs); pbs->m_next = m_free; m_free = pbs; LeaveCriticalSection(&m_cs); } else { LocalFree((HANDLE)pbuf); break; } } else break; } if (m_nbufs == nBuffers) { m_growable = (nBuffers > 0); DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: init vidpool (0x%08lX [CVidPool])\r\n", _fx_, this)); return NO_ERROR; } EnterCriticalSection(&m_cs); while (m_free) { pbs = m_free->m_next; m_free->Release(); m_free = pbs; } LeaveCriticalSection(&m_cs); } return E_OUTOFMEMORY; } STDMETHODIMP CVidPool::AddExternalBuffer( void* pBits, void* refdata ) { CBitmap* pbs; FX_ENTRY("CVidPool::AddExternalBuffer"); if (pbs = new CBitmap) { // pbs->AddRef(); - don't AddRef, because we want inpool objects to be 0 based pbs->m_bits = (LPBYTE)pBits; pbs->m_pitch = m_pitch; pbs->m_ext = TRUE; EnterCriticalSection(&m_cs); pbs->m_next = m_free; pbs->m_refdata = refdata; m_free = pbs; m_nbufs++; LeaveCriticalSection(&m_cs); DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: added bitmap (0x%08lX [CBitmap]) to vidpool (0x%08lX [CVidPool])\r\n", _fx_, pbs, this)); } return E_OUTOFMEMORY; } STDMETHODIMP CVidPool::GetBuffer( CBitmap** ppBitmap, void** prefdata ) { CBitmap* pbs = NULL; void *pbuf; FX_ENTRY("CVidPool::GetBuffer"); if (ppBitmap) { if (prefdata) *prefdata = NULL; EnterCriticalSection(&m_cs); if (pbs = m_free) { m_free = pbs->m_next; LeaveCriticalSection(&m_cs); } else { LeaveCriticalSection(&m_cs); if (m_growable) { if (pbuf = LocalAlloc(LMEM_FIXED, m_pbmh->biSizeImage)) { if (pbs = new CBitmap) { pbs->m_bits = (LPBYTE)pbuf; pbs->m_pitch = m_pitch; pbs->m_next = m_free; m_nbufs++; DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: grew vidpool (0x%08lX [CVidPool]) to %d with cbitmap (0x%08lX [CBitmap])\r\n", _fx_, this, m_nbufs, pbs)); } else LocalFree((HANDLE)pbuf); } } } if (*ppBitmap = pbs) { pbs->m_factory = this; AddRef(); pbs->AddRef(); if (prefdata) *prefdata = pbs->m_refdata; return NO_ERROR; } else return E_OUTOFMEMORY; } return E_INVALIDARG; } STDMETHODIMP CVidPool::GetBuffer( IBitmapSurface** ppBitmap, void** prefdata ) { CBitmap* pbs = NULL; GetBuffer (&pbs, prefdata); *ppBitmap = (IBitmapSurface*)pbs; return NO_ERROR; } void CVidPool::AddToFreeList( CBitmap* pBitmap ) { FX_ENTRY("CVidPool::AddToFreeList"); DEBUGMSG(ZONE_NMCAP_CDTOR,("%s: queuing cbitmap (0x%08lX [CBitmap]) to vidpool (0x%08lX [CVidPool])\r\n", _fx_, pBitmap, this)); // notify pool creator, if interested if (m_pAddingToFree) m_pAddingToFree(pBitmap, m_refdata); EnterCriticalSection(&m_cs); pBitmap->m_next = m_free; m_free = pBitmap; LeaveCriticalSection(&m_cs); pBitmap->m_factory = NULL; Release(); }