|
|
/****************************************************************************
* * cappal.c * * Palette processing module. * * 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. * ***************************************************************************/
#define INC_OLE2
#pragma warning(disable:4103)
#include <windows.h>
#include <windowsx.h>
#include <win32.h>
#include <mmsystem.h>
#include <vfw.h>
#include "ivideo32.h"
#include "avicapi.h"
#include "cappal.h"
#include "capdib.h"
#include "dibmap.h"
//
// Allocate and initialize palette resources at Window create time
//
BOOL PalInit (LPCAPSTREAM lpcs) { return (PalGetPaletteFromDriver (lpcs)); }
//
// FreePaletteCache - free the RGB555 Xlate table
//
void FreePaletteCache (LPCAPSTREAM lpcs) { if (lpcs->lpCacheXlateTable) { GlobalFreePtr (lpcs->lpCacheXlateTable); lpcs->lpCacheXlateTable = NULL; } }
//
// Release palette resources at Window destroy time
//
void PalFini (LPCAPSTREAM lpcs) { PalDeleteCurrentPalette (lpcs);
FreePaletteCache (lpcs); }
//
// Delete our palette if it isn't the system default palette
//
void PalDeleteCurrentPalette (LPCAPSTREAM lpcs) { if (lpcs->hPalCurrent && (lpcs->hPalCurrent != GetStockObject(DEFAULT_PALETTE))) DeleteObject (lpcs->hPalCurrent); lpcs->hPalCurrent = NULL; }
//
// Get the current palette (from the driver)
// Returns: TRUE if the driver can supply a palette
//
BOOL PalGetPaletteFromDriver (LPCAPSTREAM lpcs) { FCLOGPALETTE pal;
PalDeleteCurrentPalette (lpcs);
pal.palVersion = 0x0300; pal.palNumEntries = 256;
lpcs->sCapDrvCaps.fDriverSuppliesPalettes = FALSE; // assume the worst
if (lpcs->fHardwareConnected) { if (videoConfigure (lpcs->hVideoIn, DVM_PALETTE, VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT, NULL, (LPVOID)&pal, sizeof(pal), NULL, 0 ) == DV_ERR_OK) { if (lpcs->hPalCurrent = CreatePalette ((LPLOGPALETTE) &pal)) lpcs->sCapDrvCaps.fDriverSuppliesPalettes = TRUE; } } if (!lpcs->hPalCurrent) lpcs->hPalCurrent = GetStockObject (DEFAULT_PALETTE);
DibNewPalette (lpcs, lpcs->hPalCurrent);
return (lpcs->sCapDrvCaps.fDriverSuppliesPalettes); }
//
// Set the current palette used for capture by sending a copy to the driver
// and then copying the entries to out DIB.
// This may also be called when reconnecting a driver and using a cached
// copy of the palette.
// Returns TRUE on success, or FALSE on failure.
//
DWORD PalSendPaletteToDriver (LPCAPSTREAM lpcs, HPALETTE hpal, LPBYTE lpXlateTable) { short nColors; FCLOGPALETTE pal; HCURSOR hOldCursor;
// The following can take a while so repaint our parent
UpdateWindow (GetParent (lpcs-> hwnd)); UpdateWindow (lpcs->hwnd);
if (!hpal) return FALSE;
// Allocate a xlate table cache?
if (lpXlateTable) { if (lpcs->lpCacheXlateTable == NULL) { lpcs->lpCacheXlateTable = GlobalAllocPtr (GHND, 0x8000l); if (!lpcs->lpCacheXlateTable) return FALSE; }
// If we're not using the cached table, update the cache
if (lpcs->lpCacheXlateTable != lpXlateTable) _fmemcpy (lpcs->lpCacheXlateTable, lpXlateTable, (UINT) 0x8000l); } else { FreePaletteCache (lpcs); }
// Don't destroy the current palette when reconnecting...
if (hpal != lpcs->hPalCurrent) { PalDeleteCurrentPalette (lpcs); lpcs->hPalCurrent = hpal; }
GetObject(hpal, sizeof(short), (LPVOID)&nColors);
if( nColors <= 1 ) { //!!>
return( FALSE ); }
nColors = min(256, nColors);
hOldCursor = SetCursor (lpcs-> hWaitCursor);
statusUpdateStatus (lpcs, IDS_CAP_STAT_PALETTE_BUILD);
pal.palVersion = 0x0300; pal.palNumEntries = nColors;
GetPaletteEntries(hpal, 0, nColors, pal.palPalEntry);
if (lpcs-> fHardwareConnected) {
// first try to send both the xlate table and the palette
if ((!lpXlateTable) || (videoConfigure( lpcs->hVideoIn, DVM_PALETTERGB555, VIDEO_CONFIGURE_SET, NULL, (LPLOGPALETTE)&pal, sizeof(pal), lpXlateTable, (DWORD) 0x8000) != 0)) {
// else send just the palette and make the driver build the table
if (videoConfigure( lpcs->hVideoIn, DVM_PALETTE, VIDEO_CONFIGURE_SET, NULL, (LPLOGPALETTE)&pal, sizeof(pal), NULL, 0 )) { // Scrncap doesn't support setting a palette, so
// delete the palette cache
FreePaletteCache (lpcs); } } }
// Supermac wants us to get the palette again, they might have
// mucked with it!
PalGetPaletteFromDriver (lpcs);
// Since the palette has changed, delete any existing compression
// output format; this forces a new output format to be selected
if (lpcs->CompVars.lpbiOut) { GlobalFreePtr (lpcs->CompVars.lpbiOut); lpcs->CompVars.lpbiOut = NULL; } if (lpcs->CompVars.hic) { if (ICSeqCompressFrameStart(&lpcs->CompVars, lpcs->lpBitsInfo) == 0) { errorUpdateError (lpcs, IDS_CAP_COMPRESSOR_ERROR); } }
InvalidateRect (lpcs->hwnd, NULL, TRUE); UpdateWindow (lpcs->hwnd);
SetCursor (hOldCursor); statusUpdateStatus (lpcs, 0);
return (TRUE); }
//
// CopyPalette, makes a copy of a GDI logical palette
// Returns: a handle to the newly created palette, or NULL if error
//
HPALETTE CopyPalette (HPALETTE hpal) { LPLOGPALETTE lppal; short nNumEntries;
if (!hpal) return NULL;
GetObject (hpal,sizeof(short),(LPVOID)&nNumEntries);
if (nNumEntries == 0) return NULL;
lppal = (LPLOGPALETTE) GlobalAllocPtr (GHND, sizeof(LOGPALETTE) + nNumEntries * sizeof(PALETTEENTRY));
if (!lppal) return NULL;
lppal->palVersion = 0x300; lppal->palNumEntries = nNumEntries;
GetPaletteEntries(hpal,0,nNumEntries,lppal->palPalEntry);
hpal = CreatePalette(lppal);
GlobalFreePtr (lppal);
return hpal; }
//
// Allocate resources needed for palette capture
// Returns DV_ERR_OK on success, or DV_ERR... on failure.
// Note: if Init fails, you MUST call the Fini function to
// release resources.
//
DWORD CapturePaletteInit (LPCAPSTREAM lpcs, LPCAPPAL lpcp) { DWORD dwError = DV_ERR_OK;
lpcp->lpBits = NULL; lpcp->lp16to8 = NULL; lpcp->lpHistogram = NULL; lpcp->lpbiSave = NULL; lpcp->wNumFrames = 0;
// Init an RGB16 header
lpcp->bi16.biSize = sizeof(BITMAPINFOHEADER); lpcp->bi16.biWidth = lpcs->dxBits; lpcp->bi16.biHeight = lpcs->dyBits; lpcp->bi16.biPlanes = 1; lpcp->bi16.biBitCount = 16; lpcp->bi16.biCompression = BI_RGB; lpcp->bi16.biSizeImage = DIBWIDTHBYTES(lpcp->bi16) * lpcp->bi16.biHeight; lpcp->bi16.biXPelsPerMeter= 0; lpcp->bi16.biYPelsPerMeter= 0; lpcp->bi16.biClrUsed = 0; lpcp->bi16.biClrImportant = 0;
// Allocate memory for the histogram, DIB, and XLate table
lpcp->lpBits = GlobalAllocPtr (GHND, lpcp->bi16.biSizeImage); lpcp->lp16to8 = GlobalAllocPtr (GHND, 0x8000l); lpcp->lpHistogram = InitHistogram(NULL);
if (!lpcp->lpBits || !lpcp->lp16to8 || !lpcp->lpHistogram) { dwError = DV_ERR_NOMEM; goto PalInitError; }
// Init the video header
lpcp->vHdr.lpData = lpcp->lpBits; lpcp->vHdr.dwBufferLength = lpcp->bi16.biSizeImage; lpcp->vHdr.dwUser = 0; lpcp->vHdr.dwFlags = 0;
// Save the current format
lpcp->lpbiSave = DibGetCurrentFormat (lpcs);
// Make sure we can set the format to 16 bit RGB
if(dwError = videoConfigure( lpcs->hVideoIn, DVM_FORMAT, VIDEO_CONFIGURE_SET, NULL, (LPBITMAPINFOHEADER)&lpcp->bi16, sizeof(BITMAPINFOHEADER), NULL, 0 ) ) { goto PalInitError; }
// Put everything back the way it was
if (dwError = videoConfigure( lpcs->hVideoIn, DVM_FORMAT, VIDEO_CONFIGURE_SET, NULL, (LPBITMAPINFOHEADER)lpcp->lpbiSave, lpcp->lpbiSave->bmiHeader.biSize, NULL, 0 )) { goto PalInitError; }
PalInitError: return dwError; }
//
// Free resources used for palette capture
//
DWORD CapturePaletteFini (LPCAPSTREAM lpcs, LPCAPPAL lpcp) { if (lpcp->lpBits) { GlobalFreePtr (lpcp->lpBits); lpcp->lpBits = NULL; } if (lpcp->lp16to8) { GlobalFreePtr (lpcp->lp16to8); lpcp->lp16to8 = NULL; } if (lpcp->lpHistogram) { FreeHistogram(lpcp->lpHistogram); lpcp->lpHistogram = NULL; } if (lpcp->lpbiSave) { GlobalFreePtr (lpcp->lpbiSave); lpcp->lpbiSave = NULL; } return DV_ERR_OK; }
//
// CapturePaletteFrames() The workhorse of capture palette.
//
DWORD CapturePaletteFrames (LPCAPSTREAM lpcs, LPCAPPAL lpcp, int nCount) { int j; DWORD dwError;
// switch to RGB16 format
if (dwError = videoConfigure( lpcs->hVideoIn, DVM_FORMAT, VIDEO_CONFIGURE_SET, NULL, (LPBITMAPINFOHEADER)&lpcp->bi16, sizeof(BITMAPINFOHEADER), NULL, 0 )) goto CaptureFramesError;
for (j = 0; j < nCount; j++){ // Get a frame
dwError = videoFrame(lpcs->hVideoIn, &lpcp->vHdr);
// Let the user see it
InvalidateRect (lpcs->hwnd, NULL, TRUE); UpdateWindow (lpcs->hwnd);
// Histogram it
DibHistogram(&lpcp->bi16, lpcp->lpBits, 0, 0, -1, -1, lpcp->lpHistogram); lpcp->wNumFrames++; }
dwError = videoConfigure( lpcs->hVideoIn, DVM_FORMAT, VIDEO_CONFIGURE_SET, NULL, (LPBITMAPINFOHEADER)lpcp->lpbiSave, lpcp->lpbiSave->bmiHeader.biSize, NULL, 0 );
// videoFrame( lpcs->hVideoIn, &lpcs->VidHdr );
CaptureFramesError: return dwError; }
//
// CapturePaletteAuto() capture a palette from the video source
// without user intervention.
// Returns TRUE on success, FALSE on error
//
BOOL CapturePaletteAuto (LPCAPSTREAM lpcs, int nCount, int nColors) { HPALETTE hpal; HCURSOR hOldCursor; DWORD dwError = DV_ERR_OK; CAPPAL cappal; LPCAPPAL lpcp;
lpcp = &cappal;
if (!lpcs->sCapDrvCaps.fDriverSuppliesPalettes) return FALSE;
if (nColors <= 0 || nColors > 256) return FALSE;
lpcp->wNumColors = max (nColors, 2); // at least 2 colors
if (nCount <= 0) return FALSE;
if (dwError = CapturePaletteInit (lpcs, lpcp)) goto PalAutoExit;
hOldCursor = SetCursor(lpcs->hWaitCursor);
CapturePaletteFrames (lpcs, lpcp, nCount);
/* we grabbed a frame, time to compute a palette */ statusUpdateStatus(lpcs, IDS_CAP_STAT_OPTPAL_BUILD);
// The HPALETTE returned in the following becomes
// our "global" palette, hence is not deleted here.
hpal = HistogramPalette(lpcp->lpHistogram, lpcp->lp16to8, lpcp->wNumColors);
// Send driver both the pal and xlate table
PalSendPaletteToDriver(lpcs, hpal, (LPBYTE)lpcp->lp16to8 );
videoFrame( lpcs->hVideoIn, &lpcs->VidHdr ); // Update the display with a new image
SetCursor(hOldCursor);
InvalidateRect(lpcs->hwnd, NULL, TRUE); UpdateWindow(lpcs->hwnd); lpcs->fUsingDefaultPalette = FALSE;
PalAutoExit: CapturePaletteFini (lpcs, lpcp); statusUpdateStatus(lpcs, 0);
// If an error happened, display it
if (dwError) errorDriverID (lpcs, dwError);
return (dwError == DV_ERR_OK); }
//
// CapturePaletteManual() capture a palette from the video source
// with user intervention.
// fGrab is TRUE on all but the last frame captured
// Returns TRUE on success, FALSE on error
//
BOOL CapturePaletteManual (LPCAPSTREAM lpcs, BOOL fGrab, int nColors) { HPALETTE hpal; HCURSOR hOldCursor; LPCAPPAL lpcp; DWORD dwError = DV_ERR_OK;
if (!lpcs->sCapDrvCaps.fDriverSuppliesPalettes) return FALSE;
hOldCursor = SetCursor(lpcs->hWaitCursor);
// We're initializing for the first time, so alloc everything
if (lpcs->lpCapPal == NULL) {
if (lpcp = (LPCAPPAL) GlobalAllocPtr (GHND, sizeof(CAPPAL))) { lpcs->lpCapPal = lpcp;
if (nColors == 0) nColors = 256; lpcp->wNumColors = min (nColors, 256); dwError = CapturePaletteInit (lpcs, lpcp); } else dwError = IDS_CAP_OUTOFMEM; } lpcp = lpcs->lpCapPal;
if (dwError != DV_ERR_OK) goto PalManualExit;
// Add a frame to the histogram
// Handle the case of telling us to stop before we ever started
if (fGrab || !fGrab && (lpcp->wNumFrames == 0)) { CapturePaletteFrames (lpcs, lpcp, 1); lpcs->fUsingDefaultPalette = FALSE; } // All done, send the new palette to the driver
if (!fGrab) { statusUpdateStatus(lpcs, IDS_CAP_STAT_OPTPAL_BUILD);
// The HPALETTE returned in the following becomes
// our "global" palette, hence is not deleted here.
hpal = HistogramPalette(lpcp->lpHistogram, lpcp->lp16to8, lpcp->wNumColors);
// Send driver both the pal and xlate table
PalSendPaletteToDriver(lpcs, hpal, (LPBYTE)lpcp->lp16to8 ); }
videoFrame( lpcs->hVideoIn, &lpcs->VidHdr ); // Update the display with a new image
InvalidateRect(lpcs->hwnd, NULL, TRUE); UpdateWindow(lpcs->hwnd);
PalManualExit: if (!fGrab || (dwError != DV_ERR_OK)) { if (lpcp != NULL) { CapturePaletteFini (lpcs, lpcp); GlobalFreePtr (lpcp); lpcs->lpCapPal = NULL; } }
SetCursor(hOldCursor); statusUpdateStatus(lpcs, 0);
// If an error happened, display it
if (dwError) { errorUpdateError (lpcs, (UINT) dwError); }
return (dwError == DV_ERR_OK); }
/*--------------------------------------------------------------+
| fileSavePalette - save the current palette in a file | | | +--------------------------------------------------------------*/ BOOL FAR PASCAL fileSavePalette(LPCAPSTREAM lpcs, LPTSTR lpszFileName) { HPALETTE hpal; HMMIO hmmio; WORD w; HCURSOR hOldCursor; MMCKINFO ckRiff; MMCKINFO ck; short nColors; FCLOGPALETTE pal; BOOL fOK = FALSE;
if ((hpal = lpcs->hPalCurrent) == NULL) return FALSE;
hmmio = mmioOpen(lpszFileName, NULL, MMIO_WRITE); if( !hmmio ) { /* try and create */ hmmio = mmioOpen(lpszFileName, NULL, MMIO_CREATE | MMIO_WRITE); if( !hmmio ) { /* find out if the file was read only or we are just */ /* totally hosed up here. */ hmmio = mmioOpen(lpszFileName, NULL, MMIO_READ); if (hmmio){ /* file was read only, error on it */ errorUpdateError (lpcs, IDS_CAP_READONLYFILE, (LPTSTR) lpszFileName); mmioClose(hmmio, 0); return FALSE; } else { /* even weirder error has occured here, give CANTOPEN */ errorUpdateError (lpcs, IDS_CAP_CANTOPEN, (LPTSTR) lpszFileName); return FALSE; } } }
hOldCursor = SetCursor( lpcs-> hWaitCursor );
/* Seek to beginning of file, so we can write the header. */ mmioSeek(hmmio, 0, SEEK_SET);
/* Create RIFF chunk */ ckRiff.fccType = mmioFOURCC('P','A','L',' '); if(mmioCreateChunk (hmmio,&ckRiff,MMIO_CREATERIFF)) { goto FileError; }
/* Create Palette chunk */ ck.cksize = 0; ck.ckid = mmioFOURCC('d','a','t','a'); if(mmioCreateChunk(hmmio,&ck,0)) { goto FileError; }
// Get the palette data here
GetObject(hpal, sizeof(short), (LPVOID)&nColors);
pal.palVersion = 0x0300; pal.palNumEntries = nColors;
GetPaletteEntries(hpal, 0, nColors, pal.palPalEntry);
// Calc the size of the logpalette
// which is the sizeof palVersion + sizeof palNumEntries + colors
w = sizeof (WORD) + sizeof (WORD) + nColors * sizeof (PALETTEENTRY);
// Write out the palette
if(mmioWrite(hmmio, (LPBYTE)&pal, (DWORD) w) != (LONG) w) { goto FileError; }
if(mmioAscend(hmmio, &ck, 0)) { goto FileError; }
if(mmioAscend(hmmio, &ckRiff, 0)) { goto FileError; }
fOK = TRUE;
FileError: mmioClose( hmmio, 0 );
SetCursor( hOldCursor );
if (!fOK) errorUpdateError (lpcs, IDS_CAP_ERRORPALSAVE, (LPTSTR) lpszFileName);
return fOK; }
/*--------------------------------------------------------------+
| fileOpenPalette - use a new palette from the specified file | | | +--------------------------------------------------------------*/ BOOL FAR PASCAL fileOpenPalette(LPCAPSTREAM lpcs, LPTSTR lpszFileName) { HPALETTE hpal; HMMIO hmmio; WORD w; HCURSOR hOldCursor; MMCKINFO ckRiff; MMCKINFO ck; FCLOGPALETTE pal; BOOL fOK = FALSE;
if ((hpal = lpcs->hPalCurrent) == NULL) return FALSE;
hmmio = mmioOpen(lpszFileName, NULL, MMIO_READ); if( !hmmio ) { errorUpdateError (lpcs, IDS_CAP_ERRORPALOPEN, (LPTSTR) lpszFileName); return FALSE; }
hOldCursor = SetCursor( lpcs-> hWaitCursor );
/* Seek to beginning of file, so we can read the header. */ mmioSeek(hmmio, 0, SEEK_SET);
/* Find the RIFF chunk */ ckRiff.fccType = mmioFOURCC('P','A','L',' '); if(mmioDescend (hmmio, &ckRiff, NULL, MMIO_FINDRIFF)) { goto PalOpenError; }
/* Find the data chunk */ ck.cksize = 0; ck.ckid = mmioFOURCC('d','a','t','a'); if(mmioDescend (hmmio, &ck, &ckRiff, MMIO_FINDCHUNK)) { goto PalOpenError; }
// First read just the Version and number of entries
// which is the sizeof palVersion + sizeof palNumEntries
w = sizeof (WORD) + sizeof (WORD); if(mmioRead(hmmio, (LPBYTE)&pal, (DWORD) w) != (LONG) w) { goto PalOpenError; }
// Do a bit of checking
if ((pal.palVersion != 0x0300) || (pal.palNumEntries > 256)) goto PalOpenError;
// Now get the actual palette data
// which is the sizeof palVersion + sizeof palNumEntries
w = pal.palNumEntries * sizeof (PALETTEENTRY); if(mmioRead(hmmio, (LPBYTE)&pal.palPalEntry, (DWORD) w) != (LONG) w) { goto PalOpenError; }
if (hpal = CreatePalette ((LPLOGPALETTE) &pal)) { PalSendPaletteToDriver (lpcs, hpal, NULL /*lpXlateTable */); fOK = TRUE; }
videoFrame( lpcs->hVideoIn, &lpcs->VidHdr ); // grab a new frame
PalOpenError: mmioClose( hmmio, 0 );
SetCursor( hOldCursor ); InvalidateRect(lpcs->hwnd, NULL, TRUE); UpdateWindow(lpcs->hwnd); // update the display with new frame
if (!fOK) errorUpdateError (lpcs, IDS_CAP_ERRORPALOPEN, (LPTSTR) lpszFileName); else lpcs->fUsingDefaultPalette = FALSE;
return fOK; }
|