You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
12 KiB
497 lines
12 KiB
#include <windows.h>
|
|
#include <qos.h>
|
|
#include <winsock2.h>
|
|
#include "frameop.h"
|
|
#include <confdbg.h>
|
|
#include <avutil.h>
|
|
#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;
|
|
}
|
|
|
|
|