windows-nt/Source/XPSP1/NT/enduser/netmeeting/av/dcap/32nt/dcapnt.cpp

289 lines
8.7 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//
// Created 5-Nov-96 [RichP]
#include "Precomp.h"
DWORD
_GetVideoFormatSize(
HDRVR hvideo
)
{
DWORD bufsize;
VIDEOCONFIGPARMS vcp;
vcp.lpdwReturn = &bufsize;
vcp.lpData1 = NULL;
vcp.dwSize1 = 0;
vcp.lpData2 = NULL;
vcp.dwSize2 = 0L;
#if 0
// it makes sense to query if DVM_FORMAT is available, but not all drivers support it!
if (SendDriverMessage(hvideo, DVM_FORMAT,
(LPARAM)(DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_QUERY),
(LPARAM)(LPVOID)&vcp) == DV_ERR_OK) {
#endif
SendDriverMessage(hvideo, DVM_FORMAT,
(LPARAM)(DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_QUERYSIZE),
(LPARAM)(LPVOID)&vcp);
if (!bufsize)
bufsize = sizeof(BITMAPINFOHEADER);
return bufsize;
#if 0
} else
return sizeof(BITMAPINFOHEADER);
#endif
}
BOOL
_GetVideoFormat(
HVIDEO hvideo,
LPBITMAPINFOHEADER lpbmih
)
{
BOOL res;
VIDEOCONFIGPARMS vcp;
vcp.lpdwReturn = NULL;
vcp.lpData1 = lpbmih;
vcp.dwSize1 = lpbmih->biSize;
vcp.lpData2 = NULL;
vcp.dwSize2 = 0L;
res = !SendDriverMessage((HDRVR)hvideo, DVM_FORMAT,
(LPARAM)(DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT),
(LPARAM)(LPVOID)&vcp);
if (res) {
// hack for Connectix QuickCam - set format needs to be called
// to set internal globals so that streaming can be enabled
SendDriverMessage((HDRVR)hvideo, DVM_FORMAT,
(LPARAM)(DWORD)VIDEO_CONFIGURE_SET, (LPARAM)(LPVOID)&vcp);
}
return res;
}
BOOL
_SetVideoFormat(
HVIDEO hvideoExtIn,
HVIDEO hvideoIn,
LPBITMAPINFOHEADER lpbmih
)
{
RECT rect;
VIDEOCONFIGPARMS vcp;
vcp.lpdwReturn = NULL;
vcp.lpData1 = lpbmih;
vcp.dwSize1 = lpbmih->biSize;
vcp.lpData2 = NULL;
vcp.dwSize2 = 0L;
// See if the driver likes the format
if (SendDriverMessage((HDRVR)hvideoIn, DVM_FORMAT, (LPARAM)(DWORD)VIDEO_CONFIGURE_SET,
(LPARAM)(LPVOID)&vcp))
return FALSE;
// Set the rectangles
rect.left = rect.top = 0;
rect.right = (WORD)lpbmih->biWidth;
rect.bottom = (WORD)lpbmih->biHeight;
SendDriverMessage((HDRVR)hvideoExtIn, DVM_DST_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_SET);
SendDriverMessage((HDRVR)hvideoIn, DVM_SRC_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_SET);
return TRUE;
}
BOOL
_GetVideoPalette(
HVIDEO hvideo,
LPCAPTUREPALETTE lpcp,
DWORD dwcbSize
)
{
VIDEOCONFIGPARMS vcp;
vcp.lpdwReturn = NULL;
vcp.lpData1 = (LPVOID)lpcp;
vcp.dwSize1 = dwcbSize;
vcp.lpData2 = NULL;
vcp.dwSize2 = 0;
return !SendDriverMessage((HDRVR)hvideo, DVM_PALETTE,
(DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT),
(DWORD_PTR)&vcp);
}
void
FrameCallback(
HVIDEO hvideo,
WORD wMsg,
HCAPDEV hcd, // (Actually refdata)
LPCAPBUFFER lpcbuf, // (Actually LPVIDEOHDR) Only returned from MM_DRVM_DATA!
DWORD dwParam2
)
{
FX_ENTRY("FrameCallback");
DEBUGMSG(ZONE_CALLBACK, ("%s: wMsg=%s, hcd=0x%08lX, lpcbuf=0x%08lX, hcd->hevWait=0x%08lX\r\n", _fx_, (wMsg == MM_DRVM_OPEN) ? "MM_DRVM_OPEN" : (wMsg == MM_DRVM_CLOSE) ? "MM_DRVM_CLOSE" : (wMsg == MM_DRVM_ERROR) ? "MM_DRVM_ERROR" : (wMsg == MM_DRVM_DATA) ? "MM_DRVM_DATA" : "MM_DRVM_?????", hcd, lpcbuf, hcd->hevWait));
// If it's not a data ready message, just set the event and get out.
// The reason we do this is that if we get behind and start getting a stream
// of MM_DRVM_ERROR messages (usually because we're stopped in the debugger),
// we want to make sure we are getting events so we get restarted to handle
// the frames that are 'stuck.'
if (wMsg != MM_DRVM_DATA)
{
DEBUGMSG(ZONE_CALLBACK, ("%s: Setting hcd->hevWait - no data\r\n", _fx_));
SetEvent(hcd->hevWait);
return;
}
//--------------------
// Buffer ready queue:
// We maintain a doubly-linked list of our buffers so that we can buffer up
// multiple ready frames when the app isn't ready to handle them. Two things
// complicate what ought to be a very simple thing: (1) Thunking issues: the pointers
// used on the 16-bit side are 16:16 (2) Interrupt time issues: the FrameCallback
// gets called at interrupt time. GetNextReadyBuffer must handle the fact that
// buffers get added to the list asynchronously.
//
// To handle this, the scheme implemented here is to have a double-linked list
// of buffers with all insertions and deletions happening in FrameCallback
// (interrupt time). This allows the GetNextReadyBuffer routine to simply
// find the previous block on the list any time it needs a new buffer without
// fear of getting tromped (as would be the case if it had to dequeue buffers).
// The FrameCallback routine is responsible to dequeue blocks that GetNextReadyBuffer
// is done with. Dequeueing is simple since we don't need to unlink the blocks:
// no code ever walks the list! All we have to do is move the tail pointer back up
// the list. All the pointers, head, tail, next, prev, are all 16:16 pointers
// since all the list manipulation is on the 16-bit side AND because MapSL is
// much more efficient and safer than MapLS since MapLS has to allocate selectors.
//--------------------
// Move the tail back to skip all buffers already used.
// Note that there is no need to actually unhook the buffer pointers since no one
// ever walks the list!
// This makes STRICT assumptions that the current pointer will always be earlier in
// the list than the tail and that the tail will never be NULL unless the
// current pointer is too.
while (hcd->lpTail != hcd->lpCurrent)
hcd->lpTail = hcd->lpTail->lpPrev;
// If all buffers have been used, then the tail pointer will fall off the list.
// This is normal and the most common code path. In this event, just set the head
// to NULL as the list is now empty.
if (!hcd->lpTail)
hcd->lpHead = NULL;
// Add the new buffer to the ready queue
lpcbuf->lpNext = hcd->lpHead;
lpcbuf->lpPrev = NULL;
if (hcd->lpHead)
hcd->lpHead->lpPrev = lpcbuf;
else
hcd->lpTail = lpcbuf;
hcd->lpHead = lpcbuf;
#if 1
if (hcd->lpCurrent) {
if (!(hcd->dwFlags & HCAPDEV_STREAMING_PAUSED)) {
// if client hasn't consumed last frame, then release it
lpcbuf = hcd->lpCurrent;
hcd->lpCurrent = hcd->lpCurrent->lpPrev;
DEBUGMSG(ZONE_CALLBACK, ("%s: We already have current buffer (lpcbuf=0x%08lX). Returning this buffer to driver. Set new current buffer hcd->lpCurrent=0x%08lX\r\n", _fx_, lpcbuf, hcd->lpCurrent));
// Signal that the application is done with the buffer
lpcbuf->vh.dwFlags &= ~VHDR_DONE;
if (SendDriverMessage(reinterpret_cast<HDRVR>(hvideo), DVM_STREAM_ADDBUFFER, (DWORD_PTR)lpcbuf, sizeof(VIDEOHDR)) != 0)
{
ERRORMESSAGE(("%s: Attempt to reuse unconsumed buffer failed\r\n", _fx_));
}
}
}
else {
#else
if (!hcd->lpCurrent) {
// If there was no current buffer before, we have one now, so set it to the end.
#endif
hcd->lpCurrent = hcd->lpTail;
}
// Now set the event saying it's time to process the ready frame
DEBUGMSG(ZONE_CALLBACK, ("%s: Setting hcd->hevWait - some data\r\n", _fx_));
SetEvent(hcd->hevWait);
}
BOOL
_InitializeVideoStream(
HVIDEO hvideo,
DWORD dwMicroSecPerFrame,
DWORD_PTR hcd
)
{
VIDEO_STREAM_INIT_PARMS vsip;
ZeroMemory((LPSTR)&vsip, sizeof (VIDEO_STREAM_INIT_PARMS));
vsip.dwMicroSecPerFrame = dwMicroSecPerFrame;
vsip.dwCallback = (DWORD_PTR)FrameCallback;
vsip.dwCallbackInst = hcd;
vsip.dwFlags = CALLBACK_FUNCTION;
vsip.hVideo = (DWORD_PTR)hvideo;
return !SendDriverMessage((HDRVR)hvideo, DVM_STREAM_INIT,
(DWORD_PTR)&vsip,
(DWORD) sizeof (VIDEO_STREAM_INIT_PARMS));
}
BOOL
_UninitializeVideoStream(
HVIDEO hvideo
)
{
return !SendDriverMessage((HDRVR)hvideo, DVM_STREAM_FINI, 0L, 0L);
}
BOOL
_InitializeExternalVideoStream(
HVIDEO hvideo
)
{
VIDEO_STREAM_INIT_PARMS vsip;
vsip.dwMicroSecPerFrame = 0; // Ignored by driver for this channel
vsip.dwCallback = 0L; // No callback for now
vsip.dwCallbackInst = 0L;
vsip.dwFlags = 0;
vsip.hVideo = (DWORD_PTR)hvideo;
return !SendDriverMessage((HDRVR)hvideo, DVM_STREAM_INIT,
(DWORD_PTR)&vsip,
(DWORD) sizeof (VIDEO_STREAM_INIT_PARMS));
}
BOOL
_PrepareHeader(
HANDLE hvideo,
VIDEOHDR *vh
)
{
return (SendDriverMessage((HDRVR)hvideo, DVM_STREAM_PREPAREHEADER,
(DWORD_PTR)vh, (DWORD) sizeof (VIDEOHDR)) == DV_ERR_OK);
}
LRESULT
_UnprepareHeader(
HANDLE hvideo,
VIDEOHDR *vh
)
{
return SendDriverMessage((HDRVR)hvideo, DVM_STREAM_UNPREPAREHEADER,
(DWORD_PTR)vh, (DWORD) sizeof (VIDEOHDR));
}