Windows2003-3790/enduser/netmeeting/av/nmcap/vidpool.cpp
2020-09-30 16:53:55 +02:00

439 lines
10 KiB
C++

#include <windows.h>
#include <windowsx.h>
#include <objbase.h>
#include <qos.h>
#include <mmsystem.h>
#include "ibitmap.h"
#include "ividpool.h"
#include "vidpool.h"
#include <confdbg.h>
#include <avutil.h>
#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();
}