743 lines
21 KiB
C
743 lines
21 KiB
C
/****************************************************************************
|
|
*
|
|
* capdib.c
|
|
*
|
|
* DIB 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 <msvideo.h>
|
|
#include <drawdib.h>
|
|
|
|
#include "ivideo32.h"
|
|
#include "avicap.h"
|
|
#include "avicapi.h"
|
|
|
|
|
|
//
|
|
// Initialize a DIB to the default format of 160x120x8, BI_RGB
|
|
//
|
|
void SetDefaultCaptureFormat (LPBITMAPINFOHEADER lpbih)
|
|
{
|
|
lpbih->biSize = sizeof (BITMAPINFOHEADER);
|
|
lpbih->biWidth = 160;
|
|
lpbih->biHeight = 120;
|
|
lpbih->biBitCount = 8;
|
|
lpbih->biPlanes = 1;
|
|
lpbih->biCompression = BI_RGB;
|
|
lpbih->biSizeImage = DIBWIDTHBYTES (*lpbih) * lpbih->biHeight;
|
|
lpbih->biXPelsPerMeter = 0;
|
|
lpbih->biYPelsPerMeter = 0;
|
|
lpbih->biClrUsed = 256;
|
|
lpbih->biClrImportant = 0;
|
|
}
|
|
|
|
//
|
|
// Whenever we get a new format from the driver, OR
|
|
// start using a new palette, we must reallocate
|
|
// our global BITMAPINFOHEADER. This allows JPEG
|
|
// quantization tables to be tacked onto the BITMAPINFO
|
|
// or any other format specific stuff. The color table
|
|
// is always offset biSize from the start of the BITMAPINFO.
|
|
// Returns: 0 on success, or DV_ERR_... code
|
|
//
|
|
|
|
DWORD AllocNewGlobalBitmapInfo (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbi)
|
|
{
|
|
DWORD dwSize;
|
|
|
|
dwSize = lpbi->biSize + 256 * sizeof (RGBQUAD);
|
|
|
|
// The 256 entry above is HARDWIRED ON PURPOSE
|
|
// If biClrUsed was used instead, we would have to realloc
|
|
// whenever a palette is pasted (during DibNewPalette())!!!
|
|
|
|
if (lpcs->lpBitsInfo)
|
|
lpcs->lpBitsInfo = (LPBITMAPINFO) GlobalReAllocPtr (lpcs->lpBitsInfo,
|
|
dwSize, GHND);
|
|
else
|
|
lpcs->lpBitsInfo = (LPBITMAPINFO) GlobalAllocPtr (GHND, dwSize);
|
|
|
|
if (!lpcs->lpBitsInfo)
|
|
return (DV_ERR_NOMEM);
|
|
|
|
// Copy over the BITMAPINFOHEADER
|
|
CopyMemory (lpcs->lpBitsInfo, lpbi, lpbi->biSize);
|
|
|
|
return DV_ERR_OK;
|
|
}
|
|
|
|
//
|
|
// Whenever we get a new format from the driver
|
|
// allocate a new global bitspace. This bitspace is used
|
|
// in preview mode and single frame capture.
|
|
// Returns: 0 on success, or DV_ERR_... code
|
|
//
|
|
|
|
DWORD AllocNewBitSpace (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih)
|
|
{
|
|
DWORD dwSize;
|
|
|
|
// Allow room for a RIFF chunk prepended to the actual image,
|
|
// and a junk chunk on the tail end
|
|
|
|
#define RESERVE_FOR_RIFF (512+sizeof(RIFF))
|
|
|
|
dwSize = lpbih->biSizeImage + RESERVE_FOR_RIFF;
|
|
|
|
if (lpcs->lpBitsUnaligned) {
|
|
#ifdef CHICAGO
|
|
vidxFreePreviewBuffer (lpcs->hVideoIn,
|
|
lpcs->lpBitsUnaligned);
|
|
#else
|
|
FreeSectorAlignedMem (lpcs->lpBitsUnaligned);
|
|
#endif
|
|
lpcs->lpBitsUnaligned = NULL;
|
|
lpcs->lpBits = NULL;
|
|
}
|
|
|
|
#ifdef CHICAGO
|
|
if (MMSYSERR_NOERROR == vidxAllocPreviewBuffer (
|
|
lpcs->hVideoIn,
|
|
&lpcs->lpBitsUnaligned,
|
|
dwSize)) {
|
|
lpcs->lpBits = (LPBYTE) (ROUNDUPTOSECTORSIZE(lpcs->lpBitsUnaligned, 512)
|
|
+ sizeof(RIFF));
|
|
}
|
|
|
|
#else
|
|
if (lpcs->lpBitsUnaligned = ((LPBYTE)AllocSectorAlignedMem (dwSize, 512))) {
|
|
lpcs->lpBits = (LPBYTE) (ROUNDUPTOSECTORSIZE(lpcs->lpBitsUnaligned, 512)
|
|
+ sizeof(RIFF));
|
|
}
|
|
#endif
|
|
|
|
if (!lpcs->lpBits)
|
|
return (DV_ERR_NOMEM);
|
|
|
|
return DV_ERR_OK;
|
|
}
|
|
|
|
//
|
|
// Dib Initialization code
|
|
// Returns: 0 on success, or DV_ERR_... code
|
|
//
|
|
|
|
DWORD DibInit (LPCAPSTREAM lpcs)
|
|
{
|
|
BITMAPINFOHEADER bmih;
|
|
|
|
SetDefaultCaptureFormat (&bmih);
|
|
return ((WORD) AllocNewGlobalBitmapInfo (lpcs, &bmih));
|
|
}
|
|
|
|
//
|
|
// Fini code to free all bitmap resources
|
|
//
|
|
void DibFini (LPCAPSTREAM lpcs)
|
|
{
|
|
if (lpcs->lpBits) {
|
|
#ifdef CHICAGO
|
|
vidxFreePreviewBuffer (lpcs->hVideoIn, lpcs->lpBitsUnaligned);
|
|
#else
|
|
FreeSectorAlignedMem (lpcs->lpBitsUnaligned);
|
|
#endif
|
|
lpcs->lpBits = NULL;
|
|
lpcs->lpBitsUnaligned = NULL;
|
|
}
|
|
if (lpcs->lpBitsInfo) {
|
|
GlobalFreePtr (lpcs->lpBitsInfo);
|
|
lpcs->lpBitsInfo = NULL;
|
|
}
|
|
lpcs->dxBits = 0;
|
|
lpcs->dyBits = 0;
|
|
}
|
|
|
|
//
|
|
// Send a format to the driver.
|
|
// Whenever we do a format change, send the driver the
|
|
// Source and destination rects.
|
|
// Returns: 0 on success, or DV_ERR_... code
|
|
//
|
|
DWORD SendDriverFormat (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih, DWORD dwInfoHeaderSize)
|
|
{
|
|
RECT rc;
|
|
DWORD dwError = DV_ERR_NOTSUPPORTED;
|
|
|
|
rc.left = rc.top = 0;
|
|
rc.right = (int) lpbih->biWidth;
|
|
rc.bottom = (int) lpbih->biHeight;
|
|
|
|
if (dwError = videoConfigure(lpcs->hVideoIn,
|
|
DVM_FORMAT,
|
|
VIDEO_CONFIGURE_SET, NULL,
|
|
(LPBITMAPINFOHEADER)lpbih, dwInfoHeaderSize,
|
|
NULL, 0 ) ) {
|
|
return dwError;
|
|
} else {
|
|
videoSetRect (lpcs->hVideoCapture, DVM_DST_RECT, rc);
|
|
videoSetRect (lpcs->hVideoIn, DVM_SRC_RECT, rc);
|
|
videoSetRect (lpcs->hVideoIn, DVM_DST_RECT, rc);
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//
|
|
// Given a DIB, see if the driver likes it, then
|
|
// allocate the global BITMAPINFOHEADER and bitspace.
|
|
//
|
|
//
|
|
DWORD SetFormatFromDIB (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih)
|
|
{
|
|
DWORD dwError;
|
|
|
|
// Fill optional fields in the DIB header
|
|
if (lpbih->biSizeImage == 0)
|
|
lpbih->biSizeImage = DIBWIDTHBYTES (*lpbih) * lpbih->biHeight;
|
|
|
|
// Is the format palatized or full-color
|
|
if (lpbih->biBitCount <= 8 && lpbih->biClrUsed == 0)
|
|
lpbih->biClrUsed = (1 << lpbih->biBitCount); // paletized
|
|
|
|
// See if the driver will support it
|
|
if (dwError = SendDriverFormat (lpcs, lpbih, lpbih->biSize) )
|
|
return dwError;
|
|
|
|
// Realloc our global header
|
|
if (dwError = AllocNewGlobalBitmapInfo (lpcs, lpbih))
|
|
return dwError;
|
|
|
|
// Realloc the bits
|
|
if (dwError = AllocNewBitSpace (lpcs, lpbih))
|
|
return dwError;
|
|
|
|
lpcs->dxBits = (int)lpbih->biWidth;
|
|
lpcs->dyBits = (int)lpbih->biHeight;
|
|
|
|
lpcs->VidHdr.lpData = lpcs->lpBits;
|
|
lpcs->VidHdr.dwBufferLength = lpbih->biSizeImage;
|
|
lpcs->VidHdr.dwUser = 0;
|
|
lpcs->VidHdr.dwFlags = 0;
|
|
|
|
return (DV_ERR_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Returns: a LPBITMAPINFO allocated from global memory
|
|
// containing the current format, or NULL on error.
|
|
// Note that this structure can be larger than
|
|
// sizeof (BITMAPINFO), ie. JPEG !!!
|
|
//
|
|
|
|
LPBITMAPINFO DibGetCurrentFormat (LPCAPSTREAM lpcs)
|
|
{
|
|
DWORD dwError;
|
|
DWORD dwSize = 0;
|
|
LPBITMAPINFO lpBInfo = NULL;
|
|
|
|
if (!lpcs->fHardwareConnected)
|
|
return NULL;
|
|
|
|
// How large is the BITMAPINFOHEADER?
|
|
videoConfigure( lpcs->hVideoIn,
|
|
DVM_FORMAT,
|
|
VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_QUERYSIZE,
|
|
&dwSize, 0, 0, NULL, 0);
|
|
|
|
if (!dwSize)
|
|
dwSize = sizeof (BITMAPINFOHEADER);
|
|
|
|
if (!(lpBInfo = (LPBITMAPINFO) GlobalAllocPtr (GMEM_MOVEABLE, dwSize)))
|
|
return (NULL);
|
|
|
|
if (dwError = videoConfigure( lpcs->hVideoIn,
|
|
DVM_FORMAT,
|
|
VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT, NULL,
|
|
(LPBITMAPINFOHEADER) lpBInfo, dwSize,
|
|
NULL, 0 ) ) {
|
|
// very bad. the driver can't tell us its format. we're hosed.
|
|
GlobalFreePtr (lpBInfo);
|
|
return NULL;
|
|
}
|
|
|
|
return (lpBInfo);
|
|
}
|
|
|
|
//
|
|
// Main entry point when changing capture formats.
|
|
// This is called when the user closes the drivers format dialog.
|
|
// Returns: 0 on success, or DV_ERR_... code
|
|
//
|
|
DWORD DibGetNewFormatFromDriver (LPCAPSTREAM lpcs)
|
|
{
|
|
BOOL f;
|
|
BITMAPINFOHEADER bih;
|
|
DWORD dwError;
|
|
LPBITMAPINFO lpBInfo;
|
|
|
|
if (!lpcs->fHardwareConnected)
|
|
return DV_ERR_OK; // Return OK if no hardware exists
|
|
|
|
lpBInfo = DibGetCurrentFormat (lpcs);
|
|
|
|
if (lpBInfo == NULL)
|
|
return DV_ERR_NOTSUPPORTED;
|
|
|
|
// Set our internal state
|
|
if (dwError = SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER) lpBInfo)) {
|
|
// Holy shit, couldn't change formats, time to punt!
|
|
// Try to switch back to minimal format (120x160x8)
|
|
|
|
errorDriverID (lpcs, dwError);
|
|
|
|
SetDefaultCaptureFormat (&bih);
|
|
dwError = SetFormatFromDIB (lpcs, &bih);
|
|
}
|
|
|
|
// Force a new frame to be taken, so the DIB contains good
|
|
// data. Especially important to prevent codecs from exploding!
|
|
if (!dwError)
|
|
videoFrame (lpcs->hVideoIn, &lpcs->VidHdr);
|
|
|
|
if (lpBInfo)
|
|
GlobalFreePtr (lpBInfo);
|
|
|
|
f = DrawDibBegin(lpcs->hdd,NULL,-1,-1,(LPBITMAPINFOHEADER)(lpcs->lpBitsInfo),-1,-1,0);
|
|
if (!f) {
|
|
errorUpdateError(lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
|
|
}
|
|
|
|
return (dwError);
|
|
}
|
|
|
|
//
|
|
// Main entry point when changing capture formats via App message.
|
|
// Returns: TRUE on success, or FALSE if format not supported
|
|
//
|
|
BOOL DibNewFormatFromApp (LPCAPSTREAM lpcs, LPBITMAPINFO lpbiNew, UINT dwSize)
|
|
{
|
|
BOOL f;
|
|
DWORD dwError;
|
|
LPBITMAPINFO lpBInfo;
|
|
|
|
if (!lpcs->fHardwareConnected)
|
|
return FALSE;
|
|
|
|
lpBInfo = DibGetCurrentFormat (lpcs); // Allocs memory!!!
|
|
|
|
if (lpBInfo == NULL)
|
|
return FALSE;
|
|
|
|
// Set our internal state
|
|
if (dwError = SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER) lpbiNew)) {
|
|
// Driver didn't accept the format,
|
|
// switch back to the original
|
|
|
|
errorDriverID (lpcs, dwError);
|
|
|
|
SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER)lpBInfo);
|
|
}
|
|
|
|
// Force a new frame to be taken, so the DIB contains good
|
|
// data. Especially important to prevent codecs from exploding!
|
|
videoFrame (lpcs->hVideoIn, &lpcs->VidHdr);
|
|
|
|
if (lpBInfo)
|
|
GlobalFreePtr (lpBInfo);
|
|
|
|
f = DrawDibBegin(lpcs->hdd,NULL,-1,-1,(LPBITMAPINFOHEADER)(lpcs->lpBitsInfo),-1,-1,0);
|
|
if (!f) {
|
|
errorUpdateError(lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
|
|
//errorDriverID (lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
|
|
}
|
|
|
|
return (dwError == DV_ERR_OK);
|
|
}
|
|
|
|
|
|
void xlatClut8 (BYTE HUGE *pb, DWORD dwSize, BYTE HUGE *xlat)
|
|
{
|
|
DWORD dw;
|
|
|
|
for (dw = 0; dw < dwSize; dw++, ((BYTE huge *)pb)++)
|
|
*pb = xlat[*pb];
|
|
}
|
|
|
|
//
|
|
// DibNewPalette
|
|
//
|
|
// Performs three functions:
|
|
// 1. Updates the biClrUsed field if biBitCount <= 8.
|
|
// 2. Remaps BI_RGB images through a LUT when a new palette is assigned.
|
|
// 3. Copies the palette entries into our global BITMAPINFO
|
|
//
|
|
// Returns: TRUE on success
|
|
//
|
|
DWORD DibNewPalette (LPCAPSTREAM lpcs, HPALETTE hPalNew)
|
|
{
|
|
LPBITMAPINFOHEADER lpbi;
|
|
int n;
|
|
short nColors;
|
|
BYTE FAR * lpBits;
|
|
RGBQUAD FAR * lpRgb;
|
|
BYTE xlat[256];
|
|
DWORD dwSize;
|
|
PALETTEENTRY pe;
|
|
|
|
if (!hPalNew || !lpcs->lpBits || !lpcs->lpBitsInfo)
|
|
return FALSE;
|
|
|
|
lpbi = &(lpcs->lpBitsInfo->bmiHeader);
|
|
lpRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (UINT)lpbi->biSize);
|
|
lpBits = lpcs->lpBits;
|
|
|
|
GetObject(hPalNew, sizeof(short), (LPSTR) &nColors);
|
|
if (nColors > 256)
|
|
nColors = 256;
|
|
|
|
// Get the palette entries regardless of the compression
|
|
// Supermac uses non BI_RGB with a palette!
|
|
|
|
if (lpbi->biBitCount == 8) {
|
|
for (n=0; n<nColors; n++) {
|
|
GetPaletteEntries(hPalNew, n, 1, &pe);
|
|
lpRgb[n].rgbRed = pe.peRed;
|
|
lpRgb[n].rgbGreen = pe.peGreen;
|
|
lpRgb[n].rgbBlue = pe.peBlue;
|
|
}
|
|
}
|
|
|
|
if (lpbi->biBitCount == 8 && lpbi->biCompression == BI_RGB) {
|
|
|
|
//
|
|
// build a xlat table. from the old Palette to the new palette.
|
|
//
|
|
for (n=0; n<(int)lpbi->biClrUsed; n++) {
|
|
xlat[n] = (BYTE)GetNearestPaletteIndex(hPalNew,
|
|
RGB(lpRgb[n].rgbRed,lpRgb[n].rgbGreen,lpRgb[n].rgbBlue));
|
|
}
|
|
|
|
//
|
|
// translate the DIB bits
|
|
//
|
|
if ((dwSize = lpbi->biSizeImage) == 0)
|
|
dwSize = lpbi->biHeight * DIBWIDTHBYTES(*lpbi);
|
|
|
|
switch ((WORD)lpbi->biCompression)
|
|
{
|
|
case BI_RGB:
|
|
xlatClut8(lpBits, dwSize, xlat);
|
|
}
|
|
}
|
|
|
|
// Fix for Supermac, force biClrUsed to the number of palette entries
|
|
// even if non-BI_RGB formats.
|
|
|
|
if (lpbi->biBitCount <= 8)
|
|
lpbi->biClrUsed = nColors;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* DibPaint(LPCAPSTREAM lpcs, hdc)
|
|
*
|
|
* Paint the current DIB into the window;
|
|
*/
|
|
void DibPaint(LPCAPSTREAM lpcs, HDC hdc)
|
|
{
|
|
RECT rc;
|
|
BOOL fOK;
|
|
|
|
fOK = (lpcs->lpBits != NULL);
|
|
|
|
if (fOK) {
|
|
if (lpcs->fScale) {
|
|
GetClientRect(lpcs->hwnd, &rc);
|
|
fOK = DrawDibDraw(lpcs->hdd, hdc, 0, 0,
|
|
rc.right - rc.left, rc.bottom - rc.top,
|
|
(LPBITMAPINFOHEADER)lpcs->lpBitsInfo, lpcs->lpBits,
|
|
0, 0, -1, -1,
|
|
#if defined _WIN32 && defined UNICODE
|
|
0 // we don't support BACKGROUNDPAL yet in drawdib
|
|
#else
|
|
DDF_BACKGROUNDPAL
|
|
#endif
|
|
);
|
|
}
|
|
else
|
|
fOK = DrawDibDraw(lpcs->hdd, hdc, 0, 0,
|
|
lpcs->dxBits, lpcs->dyBits,
|
|
(LPBITMAPINFOHEADER)lpcs->lpBitsInfo, lpcs->lpBits,
|
|
0, 0, -1, -1,
|
|
#if defined _WIN32 && defined UNICODE
|
|
0 // we don't support BACKGROUNDPAL yet in drawdib
|
|
#else
|
|
DDF_BACKGROUNDPAL
|
|
#endif
|
|
);
|
|
|
|
}
|
|
if (!fOK) {
|
|
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
|
|
GetClientRect(lpcs->hwnd, &rc);
|
|
PatBlt(hdc, 0, 0, rc.right, rc.bottom, PATCOPY);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
* CreatePackedDib() - return the current DIB in packed (ie CF_DIB) format
|
|
*
|
|
*/
|
|
|
|
HANDLE CreatePackedDib (LPBITMAPINFO lpBitsInfo, LPSTR lpSrcBits, HPALETTE hPalette)
|
|
{
|
|
HANDLE hdib;
|
|
LPBITMAPINFO lpbi;
|
|
int i;
|
|
DWORD dwSize;
|
|
PALETTEENTRY pe;
|
|
LPBYTE lpBits;
|
|
RGBQUAD FAR * lpRgb;
|
|
|
|
// If the data is compressed, let ICM do the work for us...
|
|
if (lpBitsInfo->bmiHeader.biCompression != BI_RGB &&
|
|
lpBitsInfo->bmiHeader.biCompression != BI_RLE8 &&
|
|
(lpBitsInfo->bmiHeader.biBitCount != 8 ||
|
|
lpBitsInfo->bmiHeader.biBitCount != 24 )) {
|
|
|
|
LPBITMAPINFO lpOutFormat = NULL;
|
|
HANDLE hPackedDIBOut = NULL;
|
|
|
|
if (!(lpOutFormat = (LPBITMAPINFO)GlobalAllocPtr(
|
|
GMEM_MOVEABLE, sizeof (BITMAPINFOHEADER) +
|
|
256 * sizeof (RGBQUAD))))
|
|
return NULL;
|
|
|
|
CopyMemory (lpOutFormat, lpBitsInfo, sizeof (BITMAPINFOHEADER));
|
|
|
|
// Try to get an RGB format
|
|
lpOutFormat->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
|
|
lpOutFormat->bmiHeader.biCompression = BI_RGB;
|
|
lpOutFormat->bmiHeader.biClrUsed = 0;
|
|
lpOutFormat->bmiHeader.biClrImportant = 0;
|
|
|
|
// Uh, oh, force to a 24-bit DIB if > 8 BPP
|
|
if (lpBitsInfo->bmiHeader.biBitCount <= 8)
|
|
lpOutFormat->bmiHeader.biBitCount = 8;
|
|
else
|
|
lpOutFormat->bmiHeader.biBitCount = 24;
|
|
|
|
lpOutFormat->bmiHeader.biSizeImage =
|
|
WIDTHBYTES (lpOutFormat->bmiHeader.biWidth *
|
|
(lpOutFormat->bmiHeader.biBitCount == 8 ? 1 : 3)) *
|
|
lpOutFormat->bmiHeader.biHeight;
|
|
|
|
hPackedDIBOut = ICImageDecompress (
|
|
NULL, /*hic*/
|
|
0, /*uiFlags*/
|
|
lpBitsInfo, /*lpbiIn*/
|
|
lpSrcBits, /*lpBits*/
|
|
lpOutFormat); /*use default format chosen by compressor*/
|
|
|
|
if (lpOutFormat)
|
|
GlobalFreePtr (lpOutFormat);
|
|
|
|
return (hPackedDIBOut);
|
|
}
|
|
|
|
dwSize = lpBitsInfo->bmiHeader.biSize +
|
|
lpBitsInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD) +
|
|
lpBitsInfo->bmiHeader.biSizeImage;
|
|
|
|
hdib = GlobalAlloc(GMEM_MOVEABLE, dwSize);
|
|
|
|
if (!hdib)
|
|
return NULL;
|
|
|
|
lpbi = (LPVOID)GlobalLock(hdib);
|
|
|
|
//
|
|
// copy the header
|
|
//
|
|
CopyMemory (lpbi, lpBitsInfo, lpBitsInfo->bmiHeader.biSize);
|
|
|
|
//
|
|
// copy the color table
|
|
//
|
|
lpRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->bmiHeader.biSize);
|
|
for (i=0; i < (int)lpBitsInfo->bmiHeader.biClrUsed; i++) {
|
|
GetPaletteEntries(hPalette, i, 1, &pe);
|
|
lpRgb[i].rgbRed = pe.peRed;
|
|
lpRgb[i].rgbGreen = pe.peGreen;
|
|
lpRgb[i].rgbBlue = pe.peBlue;
|
|
lpRgb[i].rgbReserved = 0;
|
|
}
|
|
|
|
//
|
|
// copy the bits.
|
|
//
|
|
lpBits = (LPBYTE)lpbi +
|
|
lpbi->bmiHeader.biSize +
|
|
lpbi->bmiHeader.biClrUsed * sizeof(RGBQUAD);
|
|
|
|
CopyMemory (lpBits, lpSrcBits,
|
|
lpbi->bmiHeader.biSizeImage);
|
|
|
|
GlobalUnlock (hdib);
|
|
|
|
return hdib;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------+
|
|
| dibIsWritable() - return TRUE if the dib format is writable, |
|
|
| by out dibWrite() function, FALSE if not. |
|
|
| |
|
|
+---------------------------------------------------------------------*/
|
|
BOOL FAR PASCAL dibIsWritable (LPBITMAPINFO lpBitsInfo)
|
|
{
|
|
if (!lpBitsInfo)
|
|
return FALSE;
|
|
|
|
// For now, just assume that all capture formats have an installed
|
|
// codec which can convert to RGB. In the future, each time the
|
|
// format is changed, test that the codec actually accepts the format.
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------+
|
|
| dibWrite() - write out the DIB to a file. The global header is |
|
|
| in <glpBitsInfo> and the actual dib bits are in |
|
|
| <glpBits>. If it is palettized then the palette is in |
|
|
| <ghPalCurrent>. |
|
|
| |
|
|
| We won't do error reporting in this function, let the caller take |
|
|
| care of that along with Opening and Closing the HMMIO. |
|
|
| |
|
|
+---------------------------------------------------------------------*/
|
|
BOOL FAR PASCAL dibWrite(LPCAPSTREAM lpcs, HMMIO hmmio)
|
|
{
|
|
BITMAPFILEHEADER bfh;
|
|
DWORD dw;
|
|
HANDLE hPackedDib = NULL;
|
|
LPBITMAPINFO lpbi = NULL;
|
|
BOOL fOK = FALSE;
|
|
|
|
/* do some checking */
|
|
WinAssert(hmmio != 0);
|
|
|
|
if (!lpcs->lpBits || !lpcs->lpBitsInfo)
|
|
return FALSE;
|
|
|
|
// Create a packed DIB, converting from a compressed format,
|
|
// if necessary.
|
|
hPackedDib = CreatePackedDib (lpcs->lpBitsInfo,
|
|
lpcs->lpBits,
|
|
lpcs->hPalCurrent);
|
|
|
|
lpbi = (LPBITMAPINFO) GlobalLock (hPackedDib);
|
|
|
|
if (!lpbi)
|
|
goto WriteError;
|
|
|
|
/* initialize the bitmap file header */
|
|
bfh.bfType = 'B' | 'M' << 8;
|
|
bfh.bfSize = sizeof(bfh) + sizeof(BITMAPINFOHEADER) +
|
|
lpbi->bmiHeader.biSizeImage +
|
|
(lpbi->bmiHeader.biBitCount > 8 ? 0 : (lpbi->bmiHeader.biClrUsed * sizeof(RGBQUAD)));
|
|
|
|
bfh.bfReserved1 = bfh.bfReserved2 = 0;
|
|
bfh.bfOffBits = bfh.bfSize - lpbi->bmiHeader.biSizeImage ;
|
|
|
|
// dw is the size of the BITMAPINFO + color table + image
|
|
dw = bfh.bfSize - sizeof(bfh);
|
|
|
|
/* write out the file header portion */
|
|
if (mmioWrite(hmmio, (HPSTR)&bfh, (LONG)sizeof(BITMAPFILEHEADER)) !=
|
|
sizeof(BITMAPFILEHEADER)){
|
|
goto WriteError;
|
|
}
|
|
|
|
/* now write out the header and bits */
|
|
if (mmioWrite(hmmio, (HPSTR)lpbi, (LONG) dw) == (LONG) dw) {
|
|
fOK = TRUE;
|
|
}
|
|
|
|
WriteError:
|
|
if (lpbi)
|
|
GlobalUnlock (hPackedDib);
|
|
if (hPackedDib)
|
|
GlobalFree (hPackedDib);
|
|
|
|
return fOK;
|
|
}
|
|
|
|
/*--------------------------------------------------------------+
|
|
| fileSaveDIB - save the frame as a DIB |
|
|
| Top level routine to save a single frame |
|
|
+--------------------------------------------------------------*/
|
|
BOOL FAR PASCAL fileSaveDIB(LPCAPSTREAM lpcs, LPTSTR lpszFileName)
|
|
{
|
|
HMMIO hmmio;
|
|
HCURSOR hOldCursor;
|
|
BOOL fOK;
|
|
|
|
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, (LPSTR)lpszFileName);
|
|
mmioClose(hmmio, 0);
|
|
return FALSE;
|
|
} else {
|
|
/* even weirder error has occured here, give CANTOPEN */
|
|
errorUpdateError (lpcs, IDS_CAP_CANTOPEN, (LPSTR) lpszFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
hOldCursor = SetCursor( lpcs->hWaitCursor );
|
|
|
|
mmioSeek(hmmio, 0, SEEK_SET);
|
|
|
|
fOK = dibWrite(lpcs, hmmio);
|
|
|
|
mmioClose( hmmio, 0 );
|
|
|
|
SetCursor( hOldCursor );
|
|
|
|
if (!fOK)
|
|
errorUpdateError (lpcs, IDS_CAP_ERRORDIBSAVE, (LPSTR) lpszFileName);
|
|
|
|
return fOK;
|
|
}
|