windows-nt/Source/XPSP1/NT/multimedia/media/avi/avicap.16/capwin.c
2020-09-26 16:20:57 +08:00

1214 lines
38 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
*
* capwin.c
*
* Main window proceedure.
*
* Microsoft Video for Windows Sample Capture Class
*
* Copyright (c) 1992, 1993 Microsoft Corporation. All Rights Reserved.
*
* You have a royalty-free right to use, modify, reproduce and
* distribute the Sample Files (and/or any modified version) in
* any way you find useful, provided that you agree that
* Microsoft has no warranty obligations or liability for any
* Sample Application Files which are modified.
*
***************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <msvideo.h>
#include <drawdib.h>
#include <mmreg.h>
#include <memory.h>
#include "avicap.h"
#include "avicapi.h"
#include "cappal.h"
#include "capdib.h"
#include "dibmap.h"
// GetWindowLong assignments
#define GWL_CAPSTREAM 0
#define GWL_CAPVBSTATUS 4 // Used by VB Status callback
#define GWL_CAPVBERROR 8 // Used by VB Error callback
#define GWL_CAP_SPARE1 12 // Room to grow
#define GWL_CAP_SPARE2 16 // Room to grow
#define ID_PREVIEWTIMER 9
//#ifdef _DEBUG
#ifdef PLASTIQUE
#define MB(lpsz) MessageBox(NULL, lpsz, "", MB_OK);
#else
#define MB(lpsz)
#endif
//
// Set the overlay rectangles on capture cards which support
// overlay, and then enable/disable the key color.
//
static void SetOverlayRectangles (LPCAPSTREAM lpcs)
{
HDC hdc;
BOOL fVisible;
RECT rc;
if (!lpcs->hVideoDisplay)
return;
hdc = GetDC (lpcs->hwnd);
fVisible = (GetClipBox (hdc, &rc) != NULLREGION);
ReleaseDC (lpcs->hwnd, hdc);
if (!fVisible) // disable the overlay if iconic
videoStreamFini (lpcs->hVideoDisplay);
else {
// Destination
GetClientRect (lpcs->hwnd, &rc);
ClientToScreen (lpcs->hwnd, (LPPOINT)&rc);
ClientToScreen (lpcs->hwnd, (LPPOINT)&rc+1);
videoMessage (lpcs->hVideoDisplay,
DVM_DST_RECT,
(DWORD) (LPVOID) &rc, VIDEO_CONFIGURE_SET);
// Overlay channel Source rectangle
SetRect (&rc, lpcs->ptScroll.x, lpcs->ptScroll.y,
lpcs->ptScroll.x + rc.right - rc.left,
lpcs->ptScroll.y + rc.bottom - rc.top);
videoMessage (lpcs->hVideoDisplay,
DVM_SRC_RECT,
(DWORD) (LPVOID) &rc, VIDEO_CONFIGURE_SET);
videoStreamInit (lpcs->hVideoDisplay, 0L, 0L, 0L, 0L);
}
}
// WM_POSITIONCHANGED and WM_POSITIONCHANGING don't do enough to
// handle clipping of the overlay window on the Intel board,
// which keys on black. Do this routine on WM_PAINT and
// WM_ENTERIDLE messages.
void CheckWindowMove(LPCAPSTREAM lpcs, HDC hdcWnd, BOOL fForce)
{
UINT wRgn;
RECT rc;
DWORD dwOrg;
HDC hdc;
BOOL f;
if (!lpcs->hwnd || !lpcs->hVideoDisplay || !lpcs->fOverlayWindow)
return;
//
// when the screen is locked for update by a window move operation
// we dont want to turn off the video.
//
// we can tell if the screen is locked by checking a DC to the screen.
//
hdc = GetDC(NULL);
f = GetClipBox(hdc, &rc) == NULLREGION;
ReleaseDC(NULL, hdc);
if (f) {
lpcs->uiRegion = (UINT) -1;
return;
}
if (fForce)
lpcs->uiRegion = (UINT) -1;
hdc = GetDC (lpcs->hwnd);
wRgn = GetClipBox(hdc, &rc);
dwOrg = GetDCOrg(hdc);
ReleaseDC(lpcs->hwnd, hdc);
if (wRgn == lpcs->uiRegion &&
dwOrg == lpcs->dwRegionOrigin &&
EqualRect(&rc, &lpcs->rcRegionRect))
return;
lpcs->uiRegion = wRgn;
lpcs->dwRegionOrigin = dwOrg;
lpcs->rcRegionRect = rc;
SetOverlayRectangles (lpcs);
if (hdcWnd)
videoUpdate (lpcs->hVideoDisplay, lpcs->hwnd, hdcWnd);
else
InvalidateRect (lpcs->hwnd, NULL, TRUE);
}
//
// Create our little world
//
LPCAPSTREAM CapWinCreate (HWND hwnd)
{
LPCAPSTREAM lpcs;
WAVEFORMATEX wfex;
if (!(lpcs = (LPCAPSTREAM) GlobalAllocPtr (GHND, sizeof (CAPSTREAM))))
return NULL;
SetWindowLong (hwnd, GWL_CAPSTREAM, (LONG)lpcs);
lpcs-> dwSize = sizeof (CAPSTREAM);
lpcs-> uiVersion = CAPSTREAM_VERSION;
lpcs-> hwnd = hwnd;
lpcs-> hInst = ghInst;
lpcs-> hWaitCursor = LoadCursor(NULL, IDC_WAIT);
lpcs-> hdd = DrawDibOpen();
lpcs-> fAudioHardware = !!waveOutGetNumDevs(); // force 1 or 0
// Video defaults
lpcs-> sCapParms.dwRequestMicroSecPerFrame = 66667; // 15fps
lpcs-> sCapParms.vKeyAbort = VK_ESCAPE;
lpcs-> sCapParms.fAbortLeftMouse = TRUE;
lpcs-> sCapParms.fAbortRightMouse = TRUE;
lpcs-> sCapParms.wNumVideoRequested = MIN_VIDEO_BUFFERS;
lpcs-> fCapturingToDisk = TRUE;
lpcs-> sCapParms.wPercentDropForError = 10; // error msg if dropped > 10%
lpcs-> sCapParms.wChunkGranularity = 2048;
// Audio defaults to 11K, 8bit, Mono
lpcs-> sCapParms.fCaptureAudio = lpcs-> fAudioHardware;
lpcs-> sCapParms.wNumAudioRequested = DEF_WAVE_BUFFERS;
wfex.wFormatTag = WAVE_FORMAT_PCM;
wfex.nChannels = 1;
wfex.nSamplesPerSec = 11025;
wfex.nAvgBytesPerSec = 11025;
wfex.nBlockAlign = 1;
wfex.wBitsPerSample = 8;
wfex.cbSize = 0;
SendMessage (hwnd, WM_CAP_SET_AUDIOFORMAT, 0, (LONG)(LPVOID)&wfex);
// Palette defaults
lpcs-> nPaletteColors = 256;
// Capture defaults
lpcs-> sCapParms.fUsingDOSMemory = FALSE;
lstrcpy (lpcs-> achFile, "C:\\CAPTURE.AVI"); // Default capture file
lpcs->fCapFileExists = fileCapFileIsAVI (lpcs->achFile);
// Allocate index to 32K frames plus proportionate number of audio chunks
lpcs->sCapParms.dwIndexSize = (32768ul + (32768ul / 15));
lpcs->sCapParms.fDisableWriteCache = TRUE;
// Init the COMPVARS structure
lpcs->CompVars.cbSize = sizeof (COMPVARS);
lpcs->CompVars.dwFlags = 0;
return lpcs;
}
//
// Destroy our little world
//
void CapWinDestroy (LPCAPSTREAM lpcs)
{
// Uh, oh. Somebodys trying to kill us while capturing
if (lpcs->fCapturingNow && lpcs->fFrameCapturingNow) {
// Single frame capture in progress
SingleFrameCaptureClose (lpcs);
}
else if (lpcs->fCapturingNow) {
// Streaming capture in progress, OR
// MCI step capture in progress
lpcs->fAbortCapture = TRUE;
while (lpcs->fCapturingNow)
Yield ();
}
if (lpcs->idTimer)
KillTimer(lpcs->hwnd, lpcs->idTimer);
PalFini (lpcs);
DibFini (lpcs);
CapWinDisconnectHardware (lpcs);
DrawDibClose (lpcs->hdd);
if (lpcs->lpWaveFormat)
GlobalFreePtr (lpcs-> lpWaveFormat);
if (lpcs->CompVars.hic)
ICCompressorFree(&lpcs->CompVars);
if (lpcs->lpInfoChunks)
GlobalFreePtr(lpcs->lpInfoChunks);
GlobalFreePtr (lpcs); // Free the instance memory
}
WORD GetSizeOfWaveFormat (LPWAVEFORMATEX lpwf)
{
WORD wSize;
if (lpwf == NULL)
return sizeof (PCMWAVEFORMAT);
if (lpwf->wFormatTag == WAVE_FORMAT_PCM)
wSize = sizeof (PCMWAVEFORMAT);
else
wSize = sizeof (WAVEFORMATEX) + lpwf -> cbSize;
return wSize;
}
// Returns TRUE if we got a new frame, else FALSE
// if fForce, then always get a new frame
BOOL GetAFrameThenCallback (LPCAPSTREAM lpcs, BOOL fForce)
{
BOOL fOK = FALSE;
static BOOL fRecursion = FALSE;
BOOL fVisible;
RECT rc;
HDC hdc;
if (fRecursion)
return FALSE;
if (!lpcs->sCapDrvCaps.fCaptureInitialized)
return fOK;
fRecursion = TRUE;
// Update the preview window if we got a timer and not saving to disk
if (lpcs->fOverlayWindow)
CheckWindowMove(lpcs, NULL, FALSE);
if ((!lpcs->fCapturingNow) || lpcs->fStepCapturingNow || lpcs->fFrameCapturingNow) {
hdc = GetDC (lpcs->hwnd);
fVisible = (GetClipBox (hdc, &rc) != NULLREGION);
ReleaseDC (lpcs->hwnd, hdc);
if (fForce || (fVisible && (lpcs->fLiveWindow || lpcs->CallbackOnVideoFrame))) {
videoFrame (lpcs->hVideoIn, &lpcs->VidHdr );
fOK = TRUE;
if (lpcs->CallbackOnVideoFrame)
(*(lpcs->CallbackOnVideoFrame)) (lpcs->hwnd, &lpcs->VidHdr);
if (fForce || lpcs->fLiveWindow) {
InvalidateRect (lpcs->hwnd, NULL, TRUE);
UpdateWindow (lpcs->hwnd);
}
} // if visible
} // if we're not streaming
fRecursion = FALSE;
return fOK;
}
// Clear the Status and Error strings via callback
void FAR PASCAL ClearStatusAndError (LPCAPSTREAM lpcs)
{
statusUpdateStatus(lpcs, NULL); // Clear status
errorUpdateError(lpcs, NULL); // Clear error
}
// Process class specific commands >= WM_USER
DWORD PASCAL ProcessCommandMessages (LPCAPSTREAM lpcs, unsigned msg, WORD wParam, LPARAM lParam)
{
DWORD dwReturn = 0L;
DWORD dwT;
switch (msg) {
// Don't clear status and error on the following innocuous msgs
case WM_CAP_GET_CAPSTREAMPTR:
case WM_CAP_GET_USER_DATA:
case WM_CAP_DRIVER_GET_NAME:
case WM_CAP_DRIVER_GET_VERSION:
case WM_CAP_DRIVER_GET_CAPS:
case WM_CAP_GET_AUDIOFORMAT:
case WM_CAP_GET_VIDEOFORMAT:
case WM_CAP_GET_STATUS:
case WM_CAP_SET_SEQUENCE_SETUP:
case WM_CAP_GET_SEQUENCE_SETUP:
case WM_CAP_GET_MCI_DEVICE:
break;
default:
ClearStatusAndError (lpcs);
break;
}
switch (msg) {
case WM_CAP_GET_CAPSTREAMPTR:
// return a pointer to the CAPSTREAM
return (DWORD) (LPVOID) lpcs;
case WM_CAP_GET_USER_DATA:
return lpcs->lUser;
case WM_CAP_DRIVER_GET_NAME:
// Return the name of the capture driver in use
// wParam is the length of the buffer pointed to by lParam
if (!lpcs->fHardwareConnected)
return FALSE;
return (capInternalGetDriverDesc (lpcs->sCapDrvCaps.wDeviceIndex,
(LPSTR) lParam, (int) wParam, NULL, 0));
case WM_CAP_DRIVER_GET_VERSION:
// Return the version of the capture driver in use as text
// wParam is the length of the buffer pointed to by lParam
if (!lpcs->fHardwareConnected)
return FALSE;
return (capInternalGetDriverDesc (lpcs->sCapDrvCaps.wDeviceIndex,
NULL, 0, (LPSTR) lParam, (int) wParam));
case WM_CAP_DRIVER_GET_CAPS:
// wParam is the size of the CAPDRIVERCAPS struct
// lParam points to a CAPDRIVERCAPS struct
if (!lpcs->fHardwareConnected)
return FALSE;
if (wParam <= sizeof (CAPDRIVERCAPS) &&
!IsBadWritePtr ((LPVOID) lParam, (UINT) wParam)) {
dwT = min (wParam, sizeof (CAPDRIVERCAPS));
_fmemcpy ((LPVOID) lParam, (LPVOID) &lpcs-> sCapDrvCaps, (WORD) dwT);
dwReturn = TRUE;
}
break;
case WM_CAP_FILE_GET_CAPTURE_FILE:
// wParam is the size
// lParam points to a buffer in which capture file name is copied
if (lParam) {
lstrcpyn ((LPSTR) lParam, lpcs->achFile, wParam);
dwReturn = TRUE;
}
break;
case WM_CAP_GET_AUDIOFORMAT:
// if lParam == NULL, return the size
// if lParam != NULL, wParam is the size, return bytes copied
if (lpcs->lpWaveFormat == NULL)
return FALSE;
dwT = GetSizeOfWaveFormat ((LPWAVEFORMATEX) lpcs->lpWaveFormat);
if (lParam == NULL)
return (dwT);
else {
if (wParam < (WORD) dwT)
return FALSE;
else {
hmemcpy ((LPVOID) lParam, (LPVOID) lpcs->lpWaveFormat, dwT);
dwReturn = dwT;
}
}
break;
case WM_CAP_GET_MCI_DEVICE:
// wParam is the size
// lParam points to a buffer in which capture file name is copied
if (lParam) {
lstrcpyn ((LPSTR) lParam, lpcs->achMCIDevice, wParam);
dwReturn = TRUE;
}
break;
case WM_CAP_GET_STATUS:
// wParam is the size of the CAPSTATUS struct pointed to by lParam
if (!lpcs->fHardwareConnected)
return FALSE;
if (IsBadWritePtr ((LPVOID) lParam, (UINT) wParam))
return FALSE;
if (wParam >= sizeof (CAPSTATUS)) {
LPCAPSTATUS lpcc = (LPCAPSTATUS) lParam;
lpcc-> fLiveWindow = lpcs-> fLiveWindow;
lpcc-> fOverlayWindow = lpcs-> fOverlayWindow;
lpcc-> fScale = lpcs-> fScale;
lpcc-> ptScroll = lpcs-> ptScroll;
lpcc-> fUsingDefaultPalette = lpcs-> fUsingDefaultPalette;
lpcc-> fCapFileExists = lpcs-> fCapFileExists;
lpcc-> fAudioHardware = lpcs-> fAudioHardware;
lpcc-> uiImageWidth = lpcs-> dxBits;
lpcc-> uiImageHeight = lpcs-> dyBits;
// The following are updated dynamically during capture
lpcc-> dwCurrentVideoFrame = lpcs-> dwVideoChunkCount;
lpcc-> dwCurrentVideoFramesDropped = lpcs-> dwFramesDropped;
if (lpcs->lpWaveFormat != NULL) {
lpcc-> dwCurrentWaveSamples =
muldiv32 (lpcs-> dwWaveBytes,
lpcs-> lpWaveFormat-> nSamplesPerSec,
lpcs-> lpWaveFormat-> nAvgBytesPerSec);
}
lpcc-> dwCurrentTimeElapsedMS = lpcs-> dwTimeElapsedMS;
// Added post alpha release
lpcc-> fCapturingNow = lpcs-> fCapturingNow;
lpcc-> hPalCurrent = lpcs-> hPalCurrent;
lpcc-> dwReturn = lpcs-> dwReturn;
lpcc-> wNumVideoAllocated = lpcs-> iNumVideo;
lpcc-> wNumAudioAllocated = lpcs-> iNumAudio;
dwReturn = TRUE;
}
break;
case WM_CAP_GET_SEQUENCE_SETUP:
// wParam is sizeof CAPTUREPARMS
// lParam = LPCAPTUREPARMS
if (wParam <= sizeof (CAPTUREPARMS) &&
!IsBadWritePtr ((LPVOID) lParam, (UINT) wParam)) {
dwT = min (wParam, sizeof (CAPTUREPARMS));
_fmemcpy ((LPVOID) lParam, (LPVOID) &lpcs->sCapParms, (WORD) dwT);
dwReturn = TRUE;
}
break;
case WM_CAP_STOP:
// Stop capturing a sequence
if (lpcs-> fCapturingNow) {
lpcs-> fStopCapture = TRUE;
dwReturn = TRUE;
}
break;
case WM_CAP_ABORT:
// Stop capturing a sequence
if (lpcs-> fCapturingNow) {
lpcs-> fAbortCapture = TRUE;
dwReturn = TRUE;
}
break;
case WM_CAP_GET_VIDEOFORMAT:
// if lParam == NULL, return the size
// if lParam != NULL, wParam is the size, return bytes copied
if (!lpcs->fHardwareConnected)
return FALSE;
dwT = ((LPBITMAPINFOHEADER)lpcs->lpBitsInfo)-> biSize +
((LPBITMAPINFOHEADER)lpcs->lpBitsInfo)->biClrUsed * sizeof(RGBQUAD);
if (lParam == NULL)
return dwT;
else {
if (wParam < (WORD) dwT)
return FALSE;
else {
hmemcpy ((LPVOID) lParam, (LPVOID) lpcs->lpBitsInfo, dwT);
dwReturn = dwT;
}
}
break;
case WM_CAP_SINGLE_FRAME_OPEN:
// wParam is not used
// lParam is not used
if (!lpcs->fHardwareConnected)
return FALSE;
return SingleFrameCaptureOpen (lpcs);
case WM_CAP_SINGLE_FRAME_CLOSE:
// wParam is not used
// lParam is not used
if (!lpcs->fHardwareConnected)
return FALSE;
return SingleFrameCaptureClose (lpcs);
case WM_CAP_SINGLE_FRAME:
// wParam is not used
// lParam is not used
if (!lpcs->fHardwareConnected)
return FALSE;
return SingleFrameCapture (lpcs);
case WM_CAP_SET_CALLBACK_STATUS:
// Set the status callback proc
if (lParam != NULL && IsBadCodePtr ((FARPROC) lParam))
return FALSE;
lpcs->CallbackOnStatus = (CAPSTATUSCALLBACK) lParam;
return TRUE;
case WM_CAP_SET_CALLBACK_ERROR:
// Set the error callback proc
if (lParam != NULL && IsBadCodePtr ((FARPROC) lParam))
return FALSE;
lpcs->CallbackOnError = (CAPERRORCALLBACK) lParam;
return TRUE;
case WM_CAP_SET_CALLBACK_FRAME:
// Set the callback proc for single frame during preview
if (lParam != NULL && IsBadCodePtr ((FARPROC) lParam))
return FALSE;
lpcs->CallbackOnVideoFrame = (CAPVIDEOCALLBACK) lParam;
return TRUE;
default:
break;
}
// Once we start capturing, don't change anything
if (lpcs-> fCapturingNow)
return dwReturn;
switch (msg) {
case WM_CAP_SET_CALLBACK_YIELD:
// Set the callback proc for wave buffer processing to net
if (lParam != NULL && IsBadCodePtr ((FARPROC) lParam))
return FALSE;
lpcs->CallbackOnYield = (CAPYIELDCALLBACK) lParam;
return TRUE;
case WM_CAP_SET_CALLBACK_VIDEOSTREAM:
// Set the callback proc for video buffer processing to net
if (lParam != NULL && IsBadCodePtr ((FARPROC) lParam))
return FALSE;
lpcs->CallbackOnVideoStream = (CAPVIDEOCALLBACK) lParam;
return TRUE;
case WM_CAP_SET_CALLBACK_WAVESTREAM:
// Set the callback proc for wave buffer processing to net
if (lParam != NULL && IsBadCodePtr ((FARPROC) lParam))
return FALSE;
lpcs->CallbackOnWaveStream = (CAPWAVECALLBACK) lParam;
return TRUE;
case WM_CAP_SET_CALLBACK_CAPCONTROL:
// Set the callback proc for frame accurate capture start/stop
if (lParam != NULL && IsBadCodePtr ((FARPROC) lParam))
return FALSE;
lpcs->CallbackOnControl = (CAPCONTROLCALLBACK) lParam;
return TRUE;
case WM_CAP_SET_USER_DATA:
lpcs->lUser = lParam;
return TRUE;
case WM_CAP_DRIVER_CONNECT:
// Connect to a device
// wParam contains the index of the driver in system.ini
// If the same driver ID is requested, skip the request
// Prevents multiple Inits from VB apps
if (lpcs->fHardwareConnected &&
(lpcs->sCapDrvCaps.wDeviceIndex == wParam))
return TRUE;
// First disconnect from any (possibly) existing device
SendMessage (lpcs->hwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0l);
// and then connect to the new device
if (CapWinConnectHardware (lpcs, (WORD) wParam /*wDeviceIndex*/)) {
if (!DibGetNewFormatFromDriver (lpcs)) { // Allocate our bitspace
PalGetPaletteFromDriver (lpcs);
InvalidateRect(lpcs->hwnd, NULL, TRUE);
lpcs->sCapDrvCaps.fCaptureInitialized = TRUE; // everything AOK!
dwReturn = TRUE;
}
}
break;
case WM_CAP_DRIVER_DISCONNECT:
MB ("About to disconnect from driver");
// Disconnect from a device
// wParam and lParam unused
if (!lpcs->fHardwareConnected)
return FALSE;
CapWinDisconnectHardware (lpcs);
DibFini (lpcs);
PalFini (lpcs);
InvalidateRect(lpcs->hwnd, NULL, TRUE);
lpcs->sCapDrvCaps.fCaptureInitialized = FALSE;
dwReturn = TRUE;
break;
case WM_CAP_FILE_SET_CAPTURE_FILE:
// lParam points to the name of the capture file
if (lParam) {
BOOL fAlreadyExists; // Don't create a file if new name
OFSTRUCT of;
HANDLE hFile;
// Check for valid file names...
if ((hFile = OpenFile ((LPSTR) lParam, &of, OF_WRITE)) == -1) {
if ((hFile = OpenFile ((LPSTR) lParam, &of, OF_CREATE | OF_WRITE)) == -1)
return FALSE;
fAlreadyExists = FALSE;
}
else
fAlreadyExists = TRUE;
_lclose (hFile);
lstrcpyn (lpcs->achFile, (LPSTR) lParam, sizeof (lpcs->achFile));
lpcs->fCapFileExists = fileCapFileIsAVI (lpcs->achFile);
if (!fAlreadyExists)
OpenFile ((LPSTR) lParam, &of, OF_DELETE);
dwReturn = TRUE;
}
break;
case WM_CAP_FILE_ALLOCATE:
// lParam contains the size to preallocate the capture file in bytes
return fileAllocCapFile(lpcs, lParam);
case WM_CAP_FILE_SAVEAS:
// lParam points to the name of the SaveAs file
if (lParam) {
lstrcpyn (lpcs->achSaveAsFile, (LPSTR) lParam,
sizeof (lpcs->achSaveAsFile));
return (fileSaveCopy(lpcs));
}
break;
case WM_CAP_FILE_SET_INFOCHUNK:
// wParam is not used
// lParam is an LPCAPINFOCHUNK
if (lParam) {
return (SetInfoChunk(lpcs, (LPCAPINFOCHUNK) lParam));
}
break;
case WM_CAP_FILE_SAVEDIB:
// lParam points to the name of the DIB file
if (lParam) {
if (lpcs-> fOverlayWindow)
GetAFrameThenCallback (lpcs, TRUE /*fForce*/);
return (fileSaveDIB(lpcs, (LPSTR)lParam));
}
break;
case WM_CAP_EDIT_COPY:
// Copy the current image and palette to the clipboard
// wParam and lParam unused
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs-> fOverlayWindow)
GetAFrameThenCallback (lpcs, TRUE /*fForce*/);
if (lpcs->sCapDrvCaps.fCaptureInitialized && OpenClipboard (lpcs->hwnd)) {
EmptyClipboard();
// put a copy of the current palette in the clipboard
if (lpcs->hPalCurrent && lpcs->lpBitsInfo->bmiHeader.biBitCount <= 8)
SetClipboardData(CF_PALETTE, CopyPalette (lpcs->hPalCurrent));
// make a packed DIB out of the current image
if (lpcs-> lpBits && lpcs->lpBitsInfo ) {
if (SetClipboardData (CF_DIB, CreatePackedDib (lpcs->lpBitsInfo,
lpcs-> lpBits, lpcs-> hPalCurrent)))
dwReturn = TRUE;
else
errorUpdateError (lpcs, IDS_CAP_OUTOFMEM);
}
CloseClipboard();
}
break;
case WM_CAP_SET_AUDIOFORMAT:
{
// wParam is unused
// lParam is LPWAVEFORMAT or LPWAVEFORMATEX
WORD wSize;
LPWAVEFORMATEX lpwf = (LPWAVEFORMATEX) lParam;
UINT uiError;
// Verify the waveformat is valid
uiError = waveInOpen((LPHWAVEIN)NULL,
(UINT)WAVE_MAPPER, lpwf,
NULL /*hWndCallback */, 0L,
WAVE_FORMAT_QUERY);
if (uiError) {
errorUpdateError (lpcs, IDS_CAP_WAVE_OPEN_ERROR);
return FALSE;
}
if (lpcs->lpWaveFormat)
GlobalFreePtr (lpcs-> lpWaveFormat);
wSize = GetSizeOfWaveFormat (lpwf);
if (lpcs-> lpWaveFormat = (LPWAVEFORMATEX)
GlobalAllocPtr (GHND, sizeof (CAPSTREAM))) {
hmemcpy (lpcs->lpWaveFormat, lpwf, (LONG) wSize);
}
dwReturn = TRUE;
}
break;
case WM_CAP_DLG_VIDEOSOURCE:
// Show the dialog which controls the video source
// NTSC vs PAL, input channel selection, etc.
// wParam and lParam are unused
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs-> sCapDrvCaps.fHasDlgVideoSource) {
videoDialog (lpcs->hVideoCapture, lpcs->hwnd, 0L );
// Changing from NTSC to PAL could affect image dimensions!!!
DibGetNewFormatFromDriver (lpcs);
PalGetPaletteFromDriver (lpcs);
// May need to inform parent of new layout here!
InvalidateRect(lpcs->hwnd, NULL, TRUE);
UpdateWindow(lpcs->hwnd);
}
return (lpcs-> sCapDrvCaps.fHasDlgVideoSource);
case WM_CAP_DLG_VIDEOFORMAT:
// Show the format dialog, user selects dimensions, depth, compression
// wParam and lParam are unused
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs->sCapDrvCaps.fHasDlgVideoFormat) {
videoDialog (lpcs->hVideoIn, lpcs->hwnd, 0L );
DibGetNewFormatFromDriver (lpcs);
PalGetPaletteFromDriver (lpcs);
// May need to inform parent of new layout here!
InvalidateRect(lpcs->hwnd, NULL, TRUE);
UpdateWindow(lpcs->hwnd);
}
return (lpcs-> sCapDrvCaps.fHasDlgVideoFormat);
case WM_CAP_DLG_VIDEODISPLAY:
// Show the dialog which controls output.
// This dialog only affects the presentation, never the data format
// wParam and lParam are unused
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs->sCapDrvCaps.fHasDlgVideoDisplay)
videoDialog (lpcs->hVideoDisplay, lpcs->hwnd, 0L);
return (lpcs->sCapDrvCaps.fHasDlgVideoDisplay);
case WM_CAP_DLG_VIDEOCOMPRESSION:
// Show the dialog which selects video compression options.
// wParam and lParam are unused
if (!lpcs->fHardwareConnected)
return FALSE;
ICCompressorChoose(
lpcs->hwnd, // parent window for dialog
ICMF_CHOOSE_KEYFRAME, // want "key frame every" box
lpcs->lpBitsInfo, // input format (optional)
NULL, // input data (optional)
&lpcs->CompVars, // data about the compressor/dlg
NULL); // title bar (optional)
return TRUE;
case WM_CAP_SET_VIDEOFORMAT:
// wParam is the size of the BITMAPINFO
// lParam is an LPBITMAPINFO
if (!lpcs->fHardwareConnected)
return FALSE;
if (IsBadReadPtr ((LPVOID) lParam, (UINT) wParam))
return FALSE;
return (DibNewFormatFromApp (lpcs, (LPBITMAPINFO) lParam, (WORD) wParam));
case WM_CAP_SET_PREVIEW:
// if wParam, enable preview via drawdib
if (!lpcs->fHardwareConnected)
return FALSE;
if (wParam) {
// turn off the overlay, if it is in use
if (lpcs-> fOverlayWindow)
SendMessage(lpcs->hwnd, WM_CAP_SET_OVERLAY, 0, 0L);
lpcs->fLiveWindow = TRUE;
statusUpdateStatus(lpcs, IDS_CAP_STAT_LIVE_MODE);
} // endif enabling preview
else {
lpcs->fLiveWindow = FALSE;
}
InvalidateRect (lpcs->hwnd, NULL, TRUE);
return TRUE;
case WM_CAP_SET_OVERLAY:
// if wParam, enable overlay in hardware
if (!lpcs->fHardwareConnected)
return FALSE;
if (wParam && lpcs->sCapDrvCaps.fHasOverlay) {
if (lpcs-> fLiveWindow) // turn off preview mode
SendMessage(lpcs->hwnd, WM_CAP_SET_PREVIEW, 0, 0L);
lpcs->fOverlayWindow = TRUE;
statusUpdateStatus(lpcs, IDS_CAP_STAT_OVERLAY_MODE);
}
else {
lpcs->fOverlayWindow = FALSE;
videoStreamFini (lpcs->hVideoDisplay); // disable overlay on hardware
}
InvalidateRect (lpcs->hwnd, NULL, TRUE);
return (lpcs->sCapDrvCaps.fHasOverlay);
case WM_CAP_SET_PREVIEWRATE:
// wParam contains preview update rate in mS.
// if wParam == 0 no timer is in use.
if (lpcs->idTimer) {
KillTimer(lpcs->hwnd, ID_PREVIEWTIMER);
lpcs->idTimer = NULL;
}
if (wParam != 0) {
lpcs->idTimer = SetTimer (lpcs->hwnd, ID_PREVIEWTIMER,
(UINT) wParam, NULL);
}
lpcs->uTimeout = (UINT) wParam;
dwReturn = TRUE;
break;
case WM_CAP_GRAB_FRAME:
// grab a single frame
// wParam and lParam unused
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs->sCapDrvCaps.fCaptureInitialized) {
dwReturn = (DWORD) GetAFrameThenCallback (lpcs, TRUE /*fForce*/);
// disable live and overlay mode when capturing a single frame
if (lpcs->fLiveWindow)
SendMessage(lpcs->hwnd, WM_CAP_SET_PREVIEW, 0, 0L);
else if (lpcs->fOverlayWindow)
SendMessage(lpcs->hwnd, WM_CAP_SET_OVERLAY, 0, 0L);
}
break;
case WM_CAP_GRAB_FRAME_NOSTOP:
// grab a single frame, but don't change state of overlay/preview
// wParam and lParam unused
if (!lpcs->fHardwareConnected)
return FALSE;
dwReturn = (LONG) GetAFrameThenCallback (lpcs, TRUE /*fForce*/);
break;
case WM_CAP_SEQUENCE:
// This is the main entry for streaming video capture
// wParam is unused
// lParam is unused
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs->sCapDrvCaps.fCaptureInitialized) {
lpcs-> fCapturingToDisk = TRUE;
return (AVICapture(lpcs));
}
break;
case WM_CAP_SEQUENCE_NOFILE:
// wParam is unused
// lParam is unused
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs->sCapDrvCaps.fCaptureInitialized) {
lpcs-> fCapturingToDisk = FALSE;
return (AVICapture(lpcs));
}
break;
case WM_CAP_SET_SEQUENCE_SETUP:
// wParam is sizeof CAPTUREPARMS
// lParam = LPCAPTUREPARMS
// The following were added after the Beta, init in case the client
// has a smaller structure and doesn't access them.
lpcs->sCapParms.dwAudioBufferSize = 0;
lpcs->sCapParms.fDisableWriteCache = TRUE;
if (wParam <= sizeof (CAPTUREPARMS)) {
dwT = min (sizeof (CAPTUREPARMS), wParam);
if (IsBadReadPtr ((LPVOID) lParam, (UINT) dwT))
break;
_fmemcpy ((LPVOID) &lpcs->sCapParms, (LPVOID) lParam, (WORD) dwT);
// Validate stuff that isn't handled elsewhere
if (lpcs->sCapParms.wChunkGranularity < 16)
lpcs->sCapParms.wChunkGranularity = 16;
if (lpcs->sCapParms.wChunkGranularity > 16384)
lpcs->sCapParms.wChunkGranularity = 16384;
if (lpcs->sCapParms.fLimitEnabled && (lpcs->sCapParms.wTimeLimit == 0))
lpcs->sCapParms.wTimeLimit = 1;
// Force Step MCI off if not using MCI control
if (lpcs->sCapParms.fStepMCIDevice && !lpcs->sCapParms.fMCIControl)
lpcs->sCapParms.fStepMCIDevice = FALSE;
// Prevent audio capture if no audio hardware
lpcs-> sCapParms.fCaptureAudio =
lpcs-> fAudioHardware && lpcs-> sCapParms.fCaptureAudio;
// Limit audio buffers
lpcs-> sCapParms.wNumAudioRequested =
min (MAX_WAVE_BUFFERS, lpcs->sCapParms.wNumAudioRequested);
// Limit video buffers
lpcs-> sCapParms.wNumVideoRequested =
min (MAX_VIDEO_BUFFERS, lpcs->sCapParms.wNumVideoRequested);
dwReturn = TRUE;
}
break;
case WM_CAP_SET_MCI_DEVICE:
// lParam points to the name of the capture file
if (IsBadReadPtr ((LPVOID) lParam, 1))
return FALSE;
if (lParam) {
lstrcpyn (lpcs->achMCIDevice, (LPSTR) lParam, sizeof (lpcs->achMCIDevice));
dwReturn = TRUE;
}
break;
case WM_CAP_SET_SCROLL:
// lParam is an LPPOINT which contains the new scroll position
if (!lpcs->fHardwareConnected)
return FALSE;
if (IsBadReadPtr ((LPVOID) lParam, sizeof (POINT)))
return FALSE;
{
LPPOINT lpP = (LPPOINT) lParam;
if (lpP->x < lpcs-> dxBits && lpP->y < lpcs-> dyBits) {
lpcs->ptScroll = *lpP;
InvalidateRect (lpcs->hwnd, NULL, TRUE);
dwReturn = TRUE;
}
}
break;
case WM_CAP_SET_SCALE:
// if wParam, Scale the window to the client region?
if (!lpcs->fHardwareConnected)
return FALSE;
lpcs->fScale = (BOOL) wParam;
return TRUE;
case WM_CAP_PAL_OPEN:
// Open a new palette
// wParam is unused
// lParam contains an LPSTR to the file
if (!lpcs->fHardwareConnected)
return FALSE;
if (IsBadReadPtr ((LPVOID) lParam, 1))
return FALSE;
return fileOpenPalette(lpcs, (LPSTR) lParam /*lpszFileName*/);
case WM_CAP_PAL_SAVE:
// Save the current palette in a file
// wParam is unused
// lParam contains an LPSTR to the file
if (!lpcs->fHardwareConnected)
return FALSE;
if (IsBadReadPtr ((LPVOID) lParam, 1))
return FALSE;
return fileSavePalette(lpcs, (LPSTR) lParam /*lpszFileName*/);
case WM_CAP_PAL_AUTOCREATE:
// Automatically capture a palette
// wParam contains a count of the number of frames to average
// lParam contains the number of colors desired in the palette
if (!lpcs->fHardwareConnected)
return FALSE;
return CapturePaletteAuto (lpcs, (int) wParam, (int) lParam);
case WM_CAP_PAL_MANUALCREATE:
// Manually capture a palette
// wParam contains TRUE for each frame to capture, FALSE when done
// lParam contains the number of colors desired in the palette
if (!lpcs->fHardwareConnected)
return FALSE;
return CapturePaletteManual (lpcs, (BOOL) wParam, (int) lParam);
case WM_CAP_PAL_PASTE:
// Paste a palette from the clipboard, send to the driver
if (!lpcs->fHardwareConnected)
return FALSE;
if (lpcs->sCapDrvCaps.fCaptureInitialized && OpenClipboard(lpcs->hwnd)) {
HANDLE hPal;
hPal = GetClipboardData(CF_PALETTE);
CloseClipboard();
if (hPal) {
PalSendPaletteToDriver (lpcs, CopyPalette(hPal), NULL /* XlateTable */);
InvalidateRect(lpcs->hwnd, NULL, TRUE);
dwReturn = TRUE;
}
}
break;
default:
break;
}
return dwReturn;
}
/*--------------------------------------------------------------+
| ****************** THE WINDOW PROCEDURE ********************* |
+--------------------------------------------------------------*/
LONG FAR PASCAL _export _loadds CapWndProc (HWND hwnd, unsigned msg, WORD wParam, LONG lParam)
{
LPCAPSTREAM lpcs;
PAINTSTRUCT ps;
HDC hdc;
int f;
MSG PMsg;
lpcs = (LPCAPSTREAM) GetWindowLong (hwnd, GWL_CAPSTREAM);
if (msg >= WM_CAP_START && msg <= WM_CAP_END)
return (ProcessCommandMessages (lpcs, msg, wParam, lParam));
switch (msg) {
case WM_CREATE:
lpcs = CapWinCreate (hwnd);
break;
case WM_TIMER:
// Update the preview window if we got a timer and not saving to disk
GetAFrameThenCallback (lpcs, FALSE /*fForce*/);
// Added VFW 1.1b, Clear the queue of additional timer msgs???
// Trying to correct "Hit OK to continue" dialog not appearing bug
// due to app message queue continuously being full at large
// image dimensions.
PeekMessage (&PMsg, hwnd, WM_TIMER, WM_TIMER,PM_REMOVE|PM_NOYIELD);
break;
case WM_CLOSE:
break;
case WM_DESTROY:
CapWinDestroy (lpcs);
break;
case WM_PALETTECHANGED:
if (lpcs->hdd == NULL)
break;
hdc = GetDC(hwnd);
if (f = DrawDibRealize(lpcs->hdd, hdc, TRUE /*fBackground*/))
InvalidateRect(hwnd,NULL,TRUE);
ReleaseDC(hwnd,hdc);
return f;
case WM_QUERYNEWPALETTE:
if (lpcs->hdd == NULL)
break;
hdc = GetDC(hwnd);
f = DrawDibRealize(lpcs->hdd, hdc, FALSE);
ReleaseDC(hwnd, hdc);
if (f)
InvalidateRect(hwnd, NULL, TRUE);
return f;
case WM_SIZE:
case WM_MOVE:
if (lpcs->fOverlayWindow) // Make the driver paint the key color
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_WINDOWPOSCHANGED:
if (lpcs->fOverlayWindow) // Make the driver paint the key color
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_ERASEBKGND:
return 0; // don't bother to erase it
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (lpcs->fOverlayWindow) {
CheckWindowMove(lpcs, ps.hdc, TRUE);
}
else {
SetWindowOrg(hdc, lpcs->ptScroll.x, lpcs->ptScroll.y);
DibPaint(lpcs, hdc);
}
EndPaint(hwnd, &ps);
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
#if 0
void dummyTest ()
{
HWND hwnd;
FARPROC fpProc;
DWORD dwSize;
WORD wSize;
BOOL f;
int i;
char szName[80];
char szVer[80];
DWORD dwMS;
int iFrames, iColors;
char s;
LPPOINT lpP;
capSetCallbackOnError(hwnd, fpProc);
capSetCallbackOnStatus(hwnd, fpProc);
capSetCallbackOnYield(hwnd, fpProc);
capSetCallbackOnFrame(hwnd, fpProc);
capSetCallbackOnVideoStream(hwnd, fpProc);
capSetCallbackOnWaveStream(hwnd, fpProc);
capDriverConnect(hwnd, i);
capDriverDisconnect(hwnd);
capDriverGetName(hwnd, szName, wSize);
capDriverGetVersion(hwnd, szVer, wSize);
capDriverGetCaps(hwnd, s, wSize);
capFileSetCaptureFile(hwnd, szName);
capFileGetCaptureFile(hwnd, szName, wSize);
capFileAlloc(hwnd, dwSize);
capFileSaveAs(hwnd, szName);
capEditCopy(hwnd);
capSetAudioFormat(hwnd, s, wSize);
capGetAudioFormat(hwnd, s, wSize);
capGetAudioFormatSize(hwnd);
capDlgVideoFormat(hwnd);
capDlgVideoSource(hwnd);
capDlgVideoDisplay(hwnd);
capPreview(hwnd, f);
capPreviewRate(hwnd, dwMS);
capOverlay(hwnd, f);
capPreviewScale(hwnd, f);
capGetStatus(hwnd, s, wSize);
capSetScrollPos(hwnd, lpP);
capGrabFrame(hwnd);
capGrabFrameNoStop(hwnd);
capCaptureSequence(hwnd);
capCaptureSequenceNoFile(hwnd);
capCaptureGetSetup(hwnd, s, wSize);
capCaptureSetSetup(hwnd, s, wSize);
capCaptureSingleFrameOpen(hwnd);
capCaptureSingleFrameClose(hwnd);
capCaptureSingleFrame(hwnd);
capSetMCIDeviceName(hwnd, szName);
capGetMCIDeviceName(hwnd, szName, wSize);
capPalettePaste(hwnd);
capPaletteAuto(hwnd, iFrames, iColors);
}
#endif