2164 lines
69 KiB
C
2164 lines
69 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICM.C
|
||
//
|
||
// Helper routines for compressing/decompressing/and choosing compressors.
|
||
//
|
||
// (C) Copyright Microsoft Corp. 1991-1995. 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.
|
||
//
|
||
// If you did not get this from Microsoft Sources, then it may not be the
|
||
// most current version. This sample code in particular will be updated
|
||
// and include more documentation.
|
||
//
|
||
// Sources are:
|
||
// CompuServe: WINSDK forum, MDK section.
|
||
// Anonymous FTP from ftp.uu.net vendor\microsoft\multimedia
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
#pragma warning(disable:4103)
|
||
|
||
|
||
//
|
||
// define these before compman.h, so our functions get declared right.
|
||
//
|
||
#ifndef _WIN32
|
||
#define VFWAPI FAR PASCAL _loadds
|
||
#define VFWAPIV FAR CDECL _loadds
|
||
#endif
|
||
|
||
#include <win32.h>
|
||
#include <mmsystem.h>
|
||
#include <vfw.h>
|
||
|
||
#include <profile.h>
|
||
|
||
#ifdef DEBUG
|
||
static BOOL fDebug = -1;
|
||
static void CDECL dprintf(LPSTR, ...);
|
||
#define DPF(x) dprintf x
|
||
#else
|
||
#define DPF(x)
|
||
#endif
|
||
|
||
// macro to get the number of chars (byte or word) in a buffer
|
||
//
|
||
#if !defined NUMELMS
|
||
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
|
||
#endif
|
||
|
||
#define NOMMREG
|
||
#define NOMSACM
|
||
#define NOAVICAP
|
||
#include "icm.rc"
|
||
|
||
#define AVIStreamGetFrameOpen XAVIStreamGetFrameOpen
|
||
#define AVIStreamGetFrame XAVIStreamGetFrame
|
||
#define AVIStreamGetFrameClose XAVIStreamGetFrameClose
|
||
|
||
HMODULE havifile;
|
||
PGETFRAME (STDAPICALLTYPE *XAVIStreamGetFrameOpen)(PAVISTREAM pavi,
|
||
LPBITMAPINFOHEADER lpbiWanted);
|
||
LPVOID (STDAPICALLTYPE *XAVIStreamGetFrame)(PGETFRAME pgf, LONG pos);
|
||
HRESULT (STDAPICALLTYPE *XAVIStreamGetFrameClose)(PGETFRAME pgf);
|
||
|
||
#ifdef _WIN32
|
||
extern HANDLE ghInst;
|
||
#else
|
||
extern HINSTANCE ghInst;
|
||
#endif
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// DIB Macros
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
|
||
#define DibWidthBytes(lpbi) (UINT)WIDTHBYTES((UINT)(lpbi)->biWidth * (UINT)((lpbi)->biBitCount))
|
||
|
||
#define DibSizeImage(lpbi) ((DWORD)(UINT)DibWidthBytes(lpbi) * (DWORD)(UINT)((lpbi)->biHeight))
|
||
#define DibSize(lpbi) ((lpbi)->biSize + (lpbi)->biSizeImage + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
|
||
|
||
#define DibPtr(lpbi) (LPVOID)(DibColors(lpbi) + (UINT)(lpbi)->biClrUsed)
|
||
#define DibColors(lpbi) ((LPRGBQUAD)((LPBYTE)(lpbi) + (int)(lpbi)->biSize))
|
||
|
||
#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
|
||
? (int)(1 << (int)(lpbi)->biBitCount) \
|
||
: (int)(lpbi)->biClrUsed)
|
||
|
||
// !!! Someday write this so you don't have to call ICCompressorChoose if you
|
||
// !!! know what you want. Choose would then call this.
|
||
// InitCompress(pc, hic/fccHandler, lQuality, lKey, lpbiIn, lpbiOut)
|
||
|
||
/*****************************************************************************
|
||
* @doc EXTERNAL COMPVARS ICAPPS
|
||
*
|
||
* @types COMPVARS | This structure describes
|
||
* compressor when using functions such as <f ICCompressorChoose>,
|
||
* <f ICSeqCompressFrame>, or <f ICCompressorFree>.
|
||
*
|
||
* @field LONG | cbSize | Set this to the size of this structure in bytes.
|
||
* This member must be set to validate the structure
|
||
* before calling any function using this structure.
|
||
*
|
||
* @field DWORD | dwFlags | Specifies the flags for this structure:
|
||
*
|
||
* @flag ICMF_COMPVARS_VALID | Indicates this structure has valid data.
|
||
* Set this flag if you fill out this structure manually before
|
||
* calling any functions. Do not set this flag if you let
|
||
* <f ICCompressorChoose> initialize this structure.
|
||
*
|
||
* @field HIC | hic | Specifies the handle of the compressor to use.
|
||
* The <f ICCompressorChoose> function opens the chosen compressor and
|
||
* returns the handle to the compressor in this
|
||
* member. The compressor is closed by <t ICCompressorFree>.
|
||
*
|
||
* @field DWORD | fccType | Specifies the type of compressor being used.
|
||
* Currently only ICTYPE_VIDEO is supported. This can be set to zero.
|
||
*
|
||
* @field DWORD | fccHandler | Specifies the four-character code
|
||
* of the compressor. NULL indicates the data is not
|
||
* to be recompressed and and 'DIB ' indicates the data is full framed
|
||
* (uncompressed). You can use this member to specify which
|
||
* compressor is selected by default when the dialog box is
|
||
* displayed.
|
||
*
|
||
* @field LPBITMAPINFO | lpbiIn | Specifies the input format. Used internally.
|
||
*
|
||
* @field LPBITMAPINFO | lpbiOut | Specifies the output format. Ths member
|
||
* is set by <f ICCompressorChoose>. The <f ICSeqCompressFrameStart>
|
||
* function uses this member to determine the compressed output format.
|
||
* If you do not want to use the default format, specify
|
||
* the preferred one.
|
||
*
|
||
* @field LPVOID | lpBitsOut | Used internally for compression.
|
||
*
|
||
* @field LPVOID | lpBitsPrev | Used internally for temporal compression.
|
||
*
|
||
* @field LONG | lFrame | Used internally to count the number of frames
|
||
* compressed in a sequence.
|
||
*
|
||
* @field LONG | lKey | Set by <f ICCompressorChoose> to indicate the key frame
|
||
* rate selected in the dialog box. The also specifies the rate that
|
||
* <f ICSeqCompressFrameStart> uses for making key frames.
|
||
*
|
||
* @field LONG | lDataRate | Set by <f ICCompressorChoose> to indicate the
|
||
* data rate selected in the dialog box. The units are kilobytes per second.
|
||
*
|
||
* @field LONG | lQ | Set by <f ICCompressChoose> to indicate the quality
|
||
* selected in the dialog box. This also specifies the quality
|
||
* <f ICSeqCompressFrameStart> will use. ICQUALITY_DEFAULT specifies
|
||
* default quality.
|
||
*
|
||
* @field LONG | lKeyCount | Used internally to count key frames.
|
||
*
|
||
* @field LPVOID | lpState | Set by <f ICCompressorChoose> to the state selected
|
||
* in the configuration dialog box for the compressor. The system
|
||
* uses this information to restore the state of the dialog box if
|
||
* it is redisplayed. Used internally.
|
||
*
|
||
* @field LONG | cbState | Used internally for the size of the state information.
|
||
*
|
||
***************************************************************************/
|
||
/*******************************************************************
|
||
* @doc EXTERNAL ICCompressorFree ICAPPS
|
||
*
|
||
* @api void | ICCompressorFree | This function frees the resources
|
||
* in the <t COMPVARS> structure used by other IC functions.
|
||
*
|
||
* @parm PCOMPVARS | pc | Specifies a pointer to the <t COMPVARS>
|
||
* structure containing the resources to be freed.
|
||
*
|
||
* @comm After using the <f ICCompressorChoose>, <f ICSeqCompressFrameStart>,
|
||
* <f ICSeqCompressFrame>, and <f ICSeqCompressFrameEnd> functions, call
|
||
* this function to release the resources in the <t COMPVARS> structure.
|
||
*
|
||
* @xref <f ICCompressChoose> <f ICSeqCompressFrameStart> <f ICSeqCompressFrame>
|
||
* <f ICSeqCompressFrameEnd>
|
||
*
|
||
*******************************************************************/
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICCompressorFree
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
void VFWAPI ICCompressorFree(PCOMPVARS pc)
|
||
{
|
||
/* We were passed an invalid COMPPARMS */
|
||
if (pc == NULL || pc->cbSize != sizeof(COMPVARS))
|
||
return;
|
||
|
||
// This function frees every thing in the structure (excuse my
|
||
// french).
|
||
|
||
/* Close the compressor */
|
||
if (pc->hic) {
|
||
ICClose(pc->hic);
|
||
pc->hic = NULL;
|
||
}
|
||
|
||
/* Free the output format */
|
||
if (pc->lpbiOut) {
|
||
GlobalFreePtr(pc->lpbiOut);
|
||
pc->lpbiOut = NULL;
|
||
}
|
||
|
||
/* Free the buffer for compressed image */
|
||
if (pc->lpBitsOut) {
|
||
GlobalFreePtr(pc->lpBitsOut);
|
||
pc->lpBitsOut = NULL;
|
||
}
|
||
|
||
/* Free the buffer for the decompressed previous frame */
|
||
if (pc->lpBitsPrev) {
|
||
GlobalFreePtr(pc->lpBitsPrev);
|
||
pc->lpBitsPrev = NULL;
|
||
}
|
||
|
||
/* Free the compressor state buffer */
|
||
if (pc->lpState) {
|
||
GlobalFreePtr(pc->lpState);
|
||
pc->lpState = NULL;
|
||
}
|
||
|
||
/* This structure is no longer VALID */
|
||
pc->dwFlags = 0;
|
||
}
|
||
|
||
/*******************************************************************
|
||
* @doc EXTERNAL ICSeqCompressFrameStart ICAPPS
|
||
*
|
||
* @api BOOL | ICSeqCompressFrameStart | This function initializes the system
|
||
* prior to using <f ICSeqCompressFrame>.
|
||
*
|
||
* @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS> structure
|
||
* initialized with information for compression.
|
||
*
|
||
* @parm LPBITMAPINFO | lpbiIn | Specifies the format of the data to be
|
||
* compressed.
|
||
*
|
||
* @rdesc Returns TRUE if successful; otherwise it returns FALSE.
|
||
*
|
||
* @comm Prior to using this function, use <f ICCompressorChoose> to let the
|
||
* user specify a compressor, or initialize a <t COMPVARS> structure
|
||
* manually. Use <f ICSeqCompressFrameStart>, <f ICSeqCompressFrame>
|
||
* and <f ICSeqCompressFrameEnd> to compress a sequence of
|
||
* frames to a specified data rate and number of key frames.
|
||
* When finished comressing data, use
|
||
* <f ICCompressorFree> to release the resources
|
||
* specified in the <t COMPVARS> structure.
|
||
*
|
||
* If you do not use <f ICCompressorChoose> you must
|
||
* initialize the following members of the <t COMPVARS> structure:
|
||
*
|
||
* <e COMPVARS.cbSize> Set to the sizeof(COMPVARS) to validate the structure.
|
||
*
|
||
* <e COMPVARS.hic> Set to the handle of a compressor you have opened with
|
||
* <f ICOpen>. You do not need to close it (<f ICCompressorFree>
|
||
* will do this for you).
|
||
*
|
||
* <e COMPVARS.lpbiOut> Optionally set this to force the compressor
|
||
* to compress to a specific format instead of the default.
|
||
* This will be freed by <f ICCompressorFree>.
|
||
*
|
||
* <e COMPVARS.lKey> Set this to the key-frame frequency you want
|
||
* or zero for none.
|
||
*
|
||
* <e COMPVARS.lQ> Set this to the quality level to use or ICQUALITY_DEFAULT.
|
||
*
|
||
* <e COMPVARS.dwFlags> Set ICMF_COMPVARS_VALID flag to indicate the structure is initialized.
|
||
*
|
||
* @xref <f ICCompressorChoose> <f ICSeqCompressFrame> <f ICSeqCompressFrameEnd>
|
||
* <f ICCompressorFree>
|
||
*
|
||
*******************************************************************/
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICSeqCompressFrameStart
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
|
||
{
|
||
DWORD dwSize;
|
||
ICINFO icinfo;
|
||
|
||
if (pc == NULL || pc->cbSize != sizeof(COMPVARS))
|
||
return FALSE;
|
||
|
||
if (pc->hic == NULL || lpbiIn == NULL)
|
||
return FALSE;
|
||
|
||
//
|
||
// make sure the found compressor can handle something
|
||
// if not, force back to the default setting
|
||
//
|
||
if (ICCompressQuery(pc->hic, lpbiIn, pc->lpbiOut) != ICERR_OK) {
|
||
// If the input format has changed since the output was selected,
|
||
// force a reinitialization of the output format
|
||
if (pc->lpbiOut) {
|
||
GlobalFreePtr (pc->lpbiOut);
|
||
pc->lpbiOut = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// fill in defaults: key frame every frame, and default quality
|
||
//
|
||
if (pc->lKey < 0)
|
||
pc->lKey = 1;
|
||
|
||
if (pc->lQ == ICQUALITY_DEFAULT)
|
||
pc->lQ = ICGetDefaultQuality(pc->hic);
|
||
|
||
//
|
||
// If no output format is given, use a default
|
||
//
|
||
if (pc->lpbiOut == NULL) {
|
||
dwSize = ICCompressGetFormatSize(pc->hic, lpbiIn);
|
||
if (!dwSize || !(pc->lpbiOut = (LPBITMAPINFO)GlobalAllocPtr(GMEM_MOVEABLE,dwSize)))
|
||
goto StartError;
|
||
ICCompressGetFormat(pc->hic, lpbiIn, pc->lpbiOut);
|
||
}
|
||
pc->lpbiOut->bmiHeader.biSizeImage =
|
||
ICCompressGetSize (pc->hic, lpbiIn, pc->lpbiOut);
|
||
pc->lpbiOut->bmiHeader.biClrUsed = DibNumColors(&(pc->lpbiOut->bmiHeader));
|
||
|
||
//
|
||
// Set the input format and initialize the key frame count
|
||
//
|
||
pc->lpbiIn = lpbiIn;
|
||
pc->lKeyCount = pc->lKey;
|
||
pc->lFrame = 0; // first frame we'll be compressing is 0
|
||
|
||
if (ICCompressQuery(pc->hic, lpbiIn, pc->lpbiOut) != ICERR_OK)
|
||
goto StartError;
|
||
|
||
//
|
||
// Allocate a buffer for the compressed bits
|
||
//
|
||
dwSize = pc->lpbiOut->bmiHeader.biSizeImage;
|
||
|
||
// !!! Hack for VidCap... make it big enough for two RIFF structs and
|
||
// !!! pad records.
|
||
//
|
||
dwSize += 2048 + 16;
|
||
|
||
if (!(pc->lpBitsOut = GlobalAllocPtr(GMEM_MOVEABLE, dwSize)))
|
||
goto StartError;
|
||
|
||
//
|
||
// Allocate a buffer for the decompressed previous frame if it can do
|
||
// key frames and we want key frames and it needs such a buffer.
|
||
//
|
||
ICGetInfo(pc->hic, &icinfo, sizeof(icinfo));
|
||
if ((pc->lKey != 1) && (icinfo.dwFlags & VIDCF_TEMPORAL) &&
|
||
!(icinfo.dwFlags & VIDCF_FASTTEMPORALC)) {
|
||
dwSize = lpbiIn->bmiHeader.biSizeImage;
|
||
if (!(pc->lpBitsPrev = GlobalAllocPtr(GMEM_MOVEABLE, dwSize)))
|
||
goto StartError;
|
||
}
|
||
|
||
//
|
||
// now get compman ready for the big job
|
||
//
|
||
if (ICCompressBegin(pc->hic, lpbiIn, pc->lpbiOut) != ICERR_OK)
|
||
goto StartError;
|
||
|
||
//
|
||
// Get ready to decompress previous frames if we're doing key frames
|
||
// If we can't decompress, we must do all key frames
|
||
//
|
||
if (pc->lpBitsPrev) {
|
||
if (ICDecompressBegin(pc->hic, pc->lpbiOut, lpbiIn) != ICERR_OK) {
|
||
pc->lKey = pc->lKeyCount = 1;
|
||
GlobalFreePtr(pc->lpBitsPrev);
|
||
pc->lpBitsPrev = NULL;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
StartError:
|
||
|
||
// !!! Leave stuff allocated because ICCompressorFree() will clear things
|
||
return FALSE;
|
||
}
|
||
|
||
/*******************************************************************
|
||
* @doc EXTERNAL ICSeqCompressFrameEnd ICAPPS
|
||
*
|
||
* @api void | ICSeqCompressFrameEnd | This function terminates sequence
|
||
* compression using <f ICSeqCompressFrame>.
|
||
*
|
||
* @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS> structure
|
||
* used during sequence compression.
|
||
*
|
||
* @comm Use <f ICCompressorChoose> to let the
|
||
* user specify a compressor to use, or initialize a <t COMPVARS> structure
|
||
* manually. Use <f ICSeqCompressFrameStart>, <f ICSeqCompressFrame>
|
||
* and <f ICSeqCompressFrameEnd> functions to compress a sequence of
|
||
* frames to a specified data rate and number of key frames. When
|
||
* finished with compression, use <f ICCompressorFree> to
|
||
* release the resources specified by the <t COMPVARS> structure.
|
||
*
|
||
* @xref <f ICCompressorChoose> <f ICSeqCompressFrame> <f ICCompressorFree>
|
||
* <f ICSeqCompressFrameStart>
|
||
*
|
||
*******************************************************************/
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICSeqCompressFrameEnd
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
void VFWAPI ICSeqCompressFrameEnd(PCOMPVARS pc)
|
||
{
|
||
if (pc == NULL || pc->cbSize != sizeof(COMPVARS))
|
||
return;
|
||
|
||
// This function still leaves pc->hic and pc->lpbiOut alloced and open
|
||
// since they were set by ICCompressorChoose
|
||
|
||
// Seems we've already freed everything - don't call ICCompressEnd twice
|
||
if (pc->lpBitsOut == NULL)
|
||
return;
|
||
|
||
/* Stop compressing */
|
||
if (pc->hic) {
|
||
ICCompressEnd(pc->hic);
|
||
|
||
if (pc->lpBitsPrev)
|
||
ICDecompressEnd(pc->hic);
|
||
}
|
||
|
||
/* Free the buffer for compressed image */
|
||
if (pc->lpBitsOut) {
|
||
GlobalFreePtr(pc->lpBitsOut);
|
||
pc->lpBitsOut = NULL;
|
||
}
|
||
|
||
/* Free the buffer for the decompressed previous frame */
|
||
if (pc->lpBitsPrev) {
|
||
GlobalFreePtr(pc->lpBitsPrev);
|
||
pc->lpBitsPrev = NULL;
|
||
}
|
||
}
|
||
|
||
/*******************************************************************
|
||
* @doc EXTERNAL ICSeqCompressFrame ICAPPS
|
||
*
|
||
* @api LPVOID | ICSeqCompressFrame | This function compresses a
|
||
* frame in a sequence of frames. The data rate for the sequence
|
||
* as well as the key-frame frequency can be specified. Use this function
|
||
* once for each frame to be compressed.
|
||
*
|
||
* @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS> structure
|
||
* initialized with information about the compression.
|
||
*
|
||
* @parm UINT | uiFlags | Specifies flags for this function. Set this
|
||
* parameter to zero.
|
||
*
|
||
* @parm LPVOID | lpBits | Specifies a pointer the data bits to compress.
|
||
* (The data bits excludes header or format information.)
|
||
*
|
||
* @parm BOOL FAR * | pfKey | Returns whether or not the frame was compressed
|
||
* into a keyframe.
|
||
*
|
||
* @parm LONG FAR * | plSize | Specifies the maximum size desired for
|
||
* the compressed image. The compressor might not be able to
|
||
* compress the data to within this size. When the function
|
||
* returns, the parameter points to the size of the compressed
|
||
* image. Images sizes are specified in bytes.
|
||
*
|
||
* @rdesc Returns a pointer to the compressed bits.
|
||
*
|
||
* @comm Use <f ICCompressorChoose> to let the
|
||
* user specify a compressor to use, or initialize a <t COMPVARS> structure
|
||
* manually. Use <f ICSeqCompressFrameStart>, <f ICSeqCompressFrame>
|
||
* and <f ICSeqCompressFrameEnd> functions to compress a sequence of
|
||
* frames to a specified data rate and number of key frames. When
|
||
* finished with compression, use <f ICCompressorFree> to
|
||
* release the resources specified by the <t COMPVARS> structure.
|
||
*
|
||
* Use this function repeatedly to compress a video sequence one
|
||
* frame at a time. Use this function instead of <f ICCompress>
|
||
* to compress a video sequence. This function supports creating key frames
|
||
* in the compressed sequence at any frequency you like and handles
|
||
* much of the initialization process.
|
||
* @xref <f ICCompressorChoose> <f ICSeqCompressFrameEnd> <f ICCompressorFree>
|
||
* <f ICCompressorFreeStart>
|
||
*
|
||
*******************************************************************/
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICSeqCompressFrame
|
||
//
|
||
// compresses a given image but supports KEY FRAMES EVERY
|
||
//
|
||
// input:
|
||
// pc stuff
|
||
// uiFlags flags (not used, must be 0)
|
||
// lpBits input DIB bits
|
||
// lQuality the reqested compression quality
|
||
// pfKey did this frame end up being a key frame?
|
||
//
|
||
// returns:
|
||
// a HANDLE to the converted image. The handle is a DIB in CF_DIB
|
||
// format, ie a packed DIB. The caller is responsible for freeing
|
||
// the memory. NULL is returned if error.
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
LPVOID VFWAPI ICSeqCompressFrame(
|
||
PCOMPVARS pc, // junk set up by Start()
|
||
UINT uiFlags, // flags
|
||
LPVOID lpBits, // input DIB bits
|
||
BOOL FAR *pfKey, // did it end up being a key frame?
|
||
LONG FAR *plSize) // requested size/size of returned image
|
||
{
|
||
LONG l;
|
||
DWORD dwFlags = 0;
|
||
DWORD ckid = 0;
|
||
BOOL fKey;
|
||
LONG lSize = plSize ? *plSize : 0;
|
||
|
||
// Is it time to make a keyframe?
|
||
// First frame will always be a keyframe cuz they initialize to the same
|
||
// value.
|
||
|
||
if (fKey = (pc->lKeyCount >= pc->lKey)) {
|
||
// For compatibility with existing old apps
|
||
dwFlags = AVIIF_KEYFRAME;
|
||
}
|
||
|
||
l = ICCompress(pc->hic,
|
||
fKey ? ICCOMPRESS_KEYFRAME : 0, // flags
|
||
(LPBITMAPINFOHEADER)pc->lpbiOut, // output format
|
||
pc->lpBitsOut, // output data
|
||
(LPBITMAPINFOHEADER)pc->lpbiIn, // format of frame to compress
|
||
lpBits, // frame data to compress
|
||
&ckid, // ckid for data in AVI file
|
||
&dwFlags, // flags in the AVI index.
|
||
pc->lFrame, // frame number of seq.
|
||
lSize, // reqested size in bytes. (if non zero)
|
||
pc->lQ, // quality
|
||
fKey ? NULL : (LPBITMAPINFOHEADER)pc->lpbiIn, // fmt of prev frame
|
||
fKey ? NULL : pc->lpBitsPrev); // previous frame
|
||
|
||
if (l < ICERR_OK)
|
||
goto FrameError;
|
||
|
||
/* Return the size of the compressed data */
|
||
if (plSize)
|
||
*plSize = pc->lpbiOut->bmiHeader.biSizeImage;
|
||
// note: we do not reset biSizeImage... despite the fact that we
|
||
// allocated this structure, we know its size, and after compression
|
||
// the size is wrong!!
|
||
|
||
/* Now decompress the frame into our buffer for the previous frame */
|
||
if (pc->lpBitsPrev) {
|
||
l = ICDecompress(pc->hic,
|
||
0,
|
||
(LPBITMAPINFOHEADER)pc->lpbiOut,
|
||
pc->lpBitsOut,
|
||
(LPBITMAPINFOHEADER)pc->lpbiIn, // !!! should check for this.
|
||
pc->lpBitsPrev);
|
||
|
||
if (l != ICERR_OK)
|
||
goto FrameError;
|
||
}
|
||
|
||
/* Was the compressed image a keyframe? */
|
||
*pfKey = (BOOL)(dwFlags & AVIIF_KEYFRAME);
|
||
|
||
/* After making a keyframe, reset our counter that tells us when we MUST */
|
||
/* make another one. */
|
||
if (*pfKey)
|
||
pc->lKeyCount = 0;
|
||
|
||
// Never make a keyframe again after the first one if we don't want them.
|
||
// Increment our counter of how long its been since the last one if we do.
|
||
if (pc->lKey)
|
||
pc->lKeyCount++;
|
||
else
|
||
pc->lKeyCount = -1;
|
||
|
||
// Next time we're called we're on the next frame
|
||
pc->lFrame++;
|
||
|
||
return (pc->lpBitsOut);
|
||
|
||
FrameError:
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
/*******************************************************************
|
||
* @doc EXTERNAL ICImageCompress ICAPPS
|
||
*
|
||
* @api HANDLE | ICImageCompress | This function provides
|
||
* convenient method of compressing an image to a given
|
||
* size. This function does not require use of initialization functions.
|
||
*
|
||
* @parm HIC | hic | Specifies the handle to a compressor to
|
||
* opened with <f ICOpen> or NULL. Use NULL to choose a
|
||
* default compressor for your compression format.
|
||
* Applications can use the compressor handle returned
|
||
* by <f ICCompressorChoose> in the <e COMPVARS.hic> member
|
||
* of the <t COMPVARS> structure if they want the user to
|
||
* select the compressor. This compressor is already opened.
|
||
*
|
||
* @parm UINT | uiFlags | Specifies flags for this function. Set this
|
||
* to zero.
|
||
*
|
||
* @parm LPBITMAPINFO | lpbiIn | Specifies the input data format.
|
||
*
|
||
* @parm LPVOID | lpBits | Specifies a pointer to input data bits to compress.
|
||
* (The data bits excludes header or format information.)
|
||
*
|
||
* @parm LPBITMAPINFO | lpbiOut | Specifies the compressed output format or NULL.
|
||
* If NULL, the compressor uses a default format.
|
||
*
|
||
* @parm LONG | lQuality | Specifies the quality value the compressor.
|
||
*
|
||
* @parm LONG FAR * | plSize | Specifies the maximum size desired for
|
||
* the compressed image. The compressor might not be able to
|
||
* compress the data to within this size. When the function
|
||
* returns, the parameter points to the size of the compressed
|
||
* image. Images sizes are specified in bytes.
|
||
*
|
||
*
|
||
* @rdesc Returns a handle to a compressed DIB. The image data follows the
|
||
* format header.
|
||
*
|
||
* @comm This function returns a DIB with the format and image data.
|
||
* To obtain the format information from the <t LPBITMAPINFOHEADER> structure,
|
||
* use <f GlobalLock> to lock the data. Use <f GlobalFree> to free the
|
||
* DIB when you have finished with it.
|
||
*
|
||
* @xref <f ICImageDecompress>
|
||
*
|
||
*******************************************************************/
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICImageCompress
|
||
//
|
||
// compresses a given image.
|
||
//
|
||
// input:
|
||
// hic compressor to use, if NULL is specifed a
|
||
// compressor will be located that can handle the conversion.
|
||
// uiFlags flags (not used, must be 0)
|
||
// lpbiIn input DIB format
|
||
// lpBits input DIB bits
|
||
// lpbiOut output format, if NULL is specifed the default
|
||
// format choosen be the compressor will be used.
|
||
// lQuality the reqested compression quality
|
||
// plSize the reqested size for the image/returned size
|
||
//
|
||
// returns:
|
||
// a handle to a DIB which is the compressed image.
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HANDLE VFWAPI ICImageCompress(
|
||
HIC hic, // compressor (NULL if any will do)
|
||
UINT uiFlags, // flags
|
||
LPBITMAPINFO lpbiIn, // input DIB format
|
||
LPVOID lpBits, // input DIB bits
|
||
LPBITMAPINFO lpbiOut, // output format (NULL => default)
|
||
LONG lQuality, // the reqested quality
|
||
LONG FAR * plSize) // requested size for compressed frame
|
||
{
|
||
LONG l;
|
||
BOOL fNuke;
|
||
DWORD dwFlags = 0;
|
||
DWORD ckid = 0;
|
||
LONG lSize = plSize ? *plSize : 0;
|
||
|
||
LPBITMAPINFOHEADER lpbi=NULL;
|
||
|
||
//
|
||
// either locate a compressor or use the one supplied.
|
||
//
|
||
if (fNuke = (hic == NULL))
|
||
{
|
||
hic = ICLocate(ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER)lpbiIn,
|
||
(LPBITMAPINFOHEADER)lpbiOut, ICMODE_COMPRESS);
|
||
|
||
if (hic == NULL)
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// make sure the found compressor can compress something ??? WHY BOTHER ???
|
||
//
|
||
if (ICCompressQuery(hic, lpbiIn, NULL) != ICERR_OK)
|
||
goto error;
|
||
|
||
if (lpbiOut)
|
||
{
|
||
l = lpbiOut->bmiHeader.biSize + 256 * sizeof(RGBQUAD);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// now make a DIB header big enough to hold the output format
|
||
//
|
||
l = ICCompressGetFormatSize(hic, lpbiIn);
|
||
|
||
if (l <= 0)
|
||
goto error;
|
||
}
|
||
|
||
lpbi = (LPVOID)GlobalAllocPtr(GHND, l);
|
||
|
||
if (lpbi == NULL)
|
||
goto error;
|
||
|
||
//
|
||
// if the compressor likes the passed format, use it else use the default
|
||
// format of the compressor.
|
||
//
|
||
if (lpbiOut == NULL || ICCompressQuery(hic, lpbiIn, lpbiOut) != ICERR_OK)
|
||
ICCompressGetFormat(hic, lpbiIn, lpbi);
|
||
else
|
||
hmemcpy(lpbi, lpbiOut, lpbiOut->bmiHeader.biSize +
|
||
lpbiOut->bmiHeader.biClrUsed * sizeof(RGBQUAD));
|
||
|
||
lpbi->biSizeImage = ICCompressGetSize(hic, lpbiIn, lpbi);
|
||
lpbi->biClrUsed = DibNumColors(lpbi);
|
||
|
||
//
|
||
// now resize the DIB to be the maximal size.
|
||
//
|
||
lpbi = (LPVOID)GlobalReAllocPtr(lpbi,DibSize(lpbi), 0);
|
||
|
||
if (lpbi == NULL)
|
||
goto error;
|
||
|
||
//
|
||
// now compress it.
|
||
//
|
||
if (ICCompressBegin(hic, lpbiIn, lpbi) != ICERR_OK)
|
||
goto error;
|
||
|
||
if (lpBits == NULL)
|
||
lpBits = DibPtr((LPBITMAPINFOHEADER)lpbiIn);
|
||
|
||
if (lQuality == ICQUALITY_DEFAULT)
|
||
lQuality = ICGetDefaultQuality(hic);
|
||
|
||
l = ICCompress(hic,
|
||
0, // flags
|
||
(LPBITMAPINFOHEADER)lpbi, // output format
|
||
DibPtr(lpbi), // output data
|
||
(LPBITMAPINFOHEADER)lpbiIn,// format of frame to compress
|
||
lpBits, // frame data to compress
|
||
&ckid, // ckid for data in AVI file
|
||
&dwFlags, // flags in the AVI index.
|
||
0, // frame number of seq.
|
||
lSize, // requested size in bytes. (if non zero)
|
||
lQuality, // quality
|
||
NULL, // format of previous frame
|
||
NULL); // previous frame
|
||
|
||
if (l < ICERR_OK) {
|
||
DPF(("ICCompress returned %ld!\n", l));
|
||
ICCompressEnd(hic);
|
||
goto error;
|
||
}
|
||
|
||
// Return the size of the compressed data
|
||
if (plSize)
|
||
*plSize = lpbi->biSizeImage;
|
||
|
||
if (ICCompressEnd(hic) != ICERR_OK)
|
||
goto error;
|
||
|
||
//
|
||
// now resize the DIB to be the real size.
|
||
//
|
||
lpbi = (LPVOID)GlobalReAllocPtr(lpbi, DibSize(lpbi), 0);
|
||
|
||
//
|
||
// all done return the result to the caller
|
||
//
|
||
if (fNuke)
|
||
ICClose(hic);
|
||
|
||
GlobalUnlock(GlobalPtrHandle(lpbi));
|
||
return GlobalPtrHandle(lpbi);
|
||
|
||
error:
|
||
if (lpbi)
|
||
GlobalFreePtr(lpbi);
|
||
|
||
if (fNuke)
|
||
ICClose(hic);
|
||
|
||
return NULL;
|
||
}
|
||
/*******************************************************************
|
||
*
|
||
* @doc EXTERNAL ICImageDecompress ICAPPS
|
||
*
|
||
* @api HANDLE | ICImageDecompress | This function provides
|
||
* convenient method of decompressing an image without
|
||
* using initialization functions.
|
||
**
|
||
* @parm HIC | hic | Specifies the handle to a decompressor opened
|
||
* with <f ICOpen> or NULL. Use NULL to choose a default
|
||
* decompressor for your format.
|
||
*
|
||
* @parm UINT | uiFlags | Specifies flags for this function. Set this
|
||
* to zero.
|
||
*
|
||
* @parm LPBITMAPINFO | lpbiIn | Specifies the compressed input data format.
|
||
*
|
||
* @parm LPVOID | lpBits | Specifies a pointer to input data bits to compress.
|
||
* (The data bits excludes header or format information.)
|
||
*
|
||
* @parm LPBITMAPINFO | lpbiOut | Specifies the decompressed output format or NULL.
|
||
* If NULL, the decompressor uses a default format.
|
||
*
|
||
* @rdesc Returns a handle to an uncompressed DIB in the CF_DIB format,
|
||
* or NULL for an error. The image data follows the format header.
|
||
*
|
||
* @comm This function returns a DIB with the format and image data.
|
||
* To obtain the format information from the <t LPBITMAPINFOHEADER> structure,
|
||
* use <f GlobalLock> to lock the data. Use <f GlobalFree> to free the
|
||
* DIB when you have finished with it.
|
||
*
|
||
|
||
* @xref <f ICImageCompress>
|
||
*
|
||
*******************************************************************/
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICImageDecompress
|
||
//
|
||
// decompresses a given image.
|
||
//
|
||
// input:
|
||
// hic compressor to use, if NULL is specifed a
|
||
// compressor will be located that can handle the conversion.
|
||
// uiFlags flags (not used, must be 0)
|
||
// lpbiIn input DIB format
|
||
// lpBits input DIB bits
|
||
// lpbiOut output format, if NULL is specifed the default
|
||
// format choosen be the compressor will be used.
|
||
//
|
||
// returns:
|
||
// a HANDLE to the converted image. The handle is a DIB in CF_DIB
|
||
// format, ie a packed DIB. The caller is responsible for freeing
|
||
// the memory. NULL is returned if error.
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HANDLE VFWAPI ICImageDecompress(
|
||
HIC hic, // compressor (NULL if any will do)
|
||
UINT uiFlags, // flags
|
||
LPBITMAPINFO lpbiIn, // input DIB format
|
||
LPVOID lpBits, // input DIB bits
|
||
LPBITMAPINFO lpbiOut) // output format (NULL => default)
|
||
{
|
||
LONG l;
|
||
BOOL fNuke;
|
||
DWORD dwFlags = 0;
|
||
DWORD ckid = 0;
|
||
|
||
LPBITMAPINFOHEADER lpbi=NULL;
|
||
|
||
//
|
||
// either locate a compressor or use the one supplied.
|
||
//
|
||
if (fNuke = (hic == NULL))
|
||
{
|
||
hic = ICLocate(ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER)lpbiIn,
|
||
(LPBITMAPINFOHEADER)lpbiOut, ICMODE_DECOMPRESS);
|
||
|
||
if (hic == NULL)
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// make sure the found compressor can decompress at all ??? WHY BOTHER ???
|
||
//
|
||
if (ICDecompressQuery(hic, lpbiIn, NULL) != ICERR_OK)
|
||
goto error;
|
||
|
||
if (lpbiOut)
|
||
{
|
||
l = lpbiOut->bmiHeader.biSize + 256 * sizeof(RGBQUAD);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// now make a DIB header big enough to hold the output format
|
||
//
|
||
l = ICDecompressGetFormatSize(hic, lpbiIn);
|
||
|
||
if (l <= 0)
|
||
goto error;
|
||
}
|
||
|
||
lpbi = (LPVOID)GlobalAllocPtr(GHND, l);
|
||
|
||
if (lpbi == NULL)
|
||
goto error;
|
||
|
||
//
|
||
// if we didn't provide an output format, use a default.
|
||
//
|
||
if (lpbiOut == NULL)
|
||
ICDecompressGetFormat(hic, lpbiIn, lpbi);
|
||
else
|
||
hmemcpy(lpbi, lpbiOut, lpbiOut->bmiHeader.biSize +
|
||
lpbiOut->bmiHeader.biClrUsed * sizeof(RGBQUAD));
|
||
|
||
//
|
||
// For decompress make sure the palette (ie color table) is correct
|
||
// just in case they provided an output format and the decompressor used
|
||
// that format but not their palette.
|
||
//
|
||
if (lpbi->biBitCount <= 8)
|
||
ICDecompressGetPalette(hic, lpbiIn, lpbi);
|
||
|
||
lpbi->biSizeImage = DibSizeImage(lpbi); // ICDecompressGetSize(hic, lpbi);
|
||
lpbi->biClrUsed = DibNumColors(lpbi);
|
||
|
||
//
|
||
// now resize the DIB to be the right size.
|
||
//
|
||
lpbi = (LPVOID)GlobalReAllocPtr(lpbi,DibSize(lpbi),0);
|
||
|
||
if (lpbi == NULL)
|
||
goto error;
|
||
|
||
//
|
||
// now decompress it.
|
||
//
|
||
if (ICDecompressBegin(hic, lpbiIn, lpbi) != ICERR_OK)
|
||
goto error;
|
||
|
||
if (lpBits == NULL)
|
||
lpBits = DibPtr((LPBITMAPINFOHEADER)lpbiIn);
|
||
|
||
l = ICDecompress(hic,
|
||
0, // flags
|
||
(LPBITMAPINFOHEADER)lpbiIn, // format of frame to decompress
|
||
lpBits, // frame data to decompress
|
||
(LPBITMAPINFOHEADER)lpbi, // output format
|
||
DibPtr(lpbi)); // output data
|
||
|
||
if (l < ICERR_OK) {
|
||
ICDecompressEnd(hic);
|
||
goto error;
|
||
}
|
||
|
||
if (ICDecompressEnd(hic) != ICERR_OK)
|
||
goto error;
|
||
|
||
//
|
||
// now resize the DIB to be the real size.
|
||
//
|
||
lpbi = (LPVOID)GlobalReAllocPtr(lpbi,DibSize(lpbi),0);
|
||
|
||
//
|
||
// all done return the result to the caller
|
||
//
|
||
if (fNuke)
|
||
ICClose(hic);
|
||
|
||
GlobalUnlock(GlobalPtrHandle(lpbi));
|
||
return GlobalPtrHandle(lpbi);
|
||
|
||
error:
|
||
if (lpbi)
|
||
GlobalFreePtr(lpbi);
|
||
|
||
if (fNuke)
|
||
ICClose(hic);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICCompressorChooseStuff
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
INT_PTR VFWAPI ICCompressorChooseDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||
|
||
typedef struct {
|
||
DWORD fccType;
|
||
DWORD fccHandler;
|
||
UINT uiFlags;
|
||
LPVOID pvIn;
|
||
LPVOID lpData;
|
||
HWND hwnd;
|
||
HIC hic;
|
||
LONG lQ;
|
||
LONG lKey;
|
||
LONG lDataRate;
|
||
ICINFO icinfo;
|
||
LPSTR lpszTitle;
|
||
PAVISTREAM pavi;
|
||
AVISTREAMINFOW info;
|
||
HDRAWDIB hdd;
|
||
PGETFRAME pgf;
|
||
LPVOID lpState;
|
||
LONG cbState;
|
||
BOOL fClosing;
|
||
} ICCompressorChooseStuff, FAR *PICCompressorChooseStuff;
|
||
|
||
/*******************************************************************
|
||
* @doc EXTERNAL ICCompressorChoose ICAPPS
|
||
*
|
||
* @api BOOL | ICCompressorChoose | Displays a dialog box for choosing a
|
||
* compressor. It optionally provides a data rate box, key frame box, preview
|
||
* window, and filtering to display only compressors that can handle a
|
||
* specific format.
|
||
*
|
||
* @parm HWND | hwnd | Specifies the parent window for the dialog box.
|
||
*
|
||
* @parm UINT | uiFlags | Specifies flags for this function. The following
|
||
* flags are defined:
|
||
*
|
||
* @flag ICMF_CHOOSE_KEYFRAME | Displays a check box and edit box to enter the
|
||
* frequency of key frames.
|
||
*
|
||
* @flag ICMF_CHOOSE_DATARATE | Displays a check box and edit box to enter the
|
||
* data rate for the movie.
|
||
*
|
||
* @flag ICMF_CHOOSE_PREVIEW | Displays a button to expand the dialog box to
|
||
* include a preview window. The preview window shows how
|
||
* frames of your movie will appear when compressed with the
|
||
* current settings.
|
||
*
|
||
* @flag ICMF_CHOOSE_ALLCOMPRESSORS | Indicates all compressors should
|
||
* should appear in the selection list. If this flag is not specified,
|
||
* just the compressors that can handle the input format appear in
|
||
* the selection list.
|
||
*
|
||
* @parm LPVOID | pvIn | Specifies the uncompressed
|
||
* data input format. This parameter is optional.
|
||
*
|
||
* @parm LPVOID | lpData | Specifies a <t PAVISTREAM> of type
|
||
* streamtypeVIDEO to use in the preview window. This parameter
|
||
* is optional.
|
||
*
|
||
* @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS>
|
||
* structure. The information returned initializes the
|
||
* structure for use with other functions.
|
||
*
|
||
* @parm LPSTR | lpszTitle | Points to a optional zero-terminated string
|
||
* containing a title for the dialog box.
|
||
*
|
||
* @rdesc Returns TRUE if the user chooses a compressor, and presses OK. Returns
|
||
* FALSE for an error, or if the user presses CANCEL.
|
||
*
|
||
* @comm This function lets the user select a compressor from a list.
|
||
* Before using it, set the <e COMPVARS.cbSize> member of the <t COMPVARS>
|
||
* structure to sizeof(COMPVARS). Initialize the rest of the structure
|
||
* to zeros unless you want to specify some valid defaults for
|
||
* the dialog box. If specifing defaults, set the <e COMPVARS.dwFlags>
|
||
* member to ICMF_COMPVARS_VALID, and initialize the other members of
|
||
* the structure. See <f ICSeqCompressorFrameStart> and <t COMPVARS>
|
||
* for more information about initializing the structure.
|
||
*
|
||
* @xref <f ICCompressorFree> <f ICSeqCompressFrameStart> <f ICSeqCompressFrame>
|
||
* <f ICSeqCompressFrameEnd>
|
||
*
|
||
*******************************************************************/
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICCompressorChoose
|
||
//
|
||
// Brings up a dialog and allows the user to choose a compression
|
||
// method and a quality level, and/or a key frame frequency.
|
||
// All compressors in the system are displayed or can be optionally
|
||
// filtered by "ability to compress" a specifed format.
|
||
//
|
||
// the dialog allows the user to configure or bring up the compressors
|
||
// about box.
|
||
//
|
||
// A preview window can be provided to show a preview of a specific
|
||
// compression.
|
||
//
|
||
// the selected compressor is opened (via ICOpen) and returned to the
|
||
// caller, it must be disposed of by calling ICCompressorFree.
|
||
//
|
||
// input:
|
||
// HWND hwnd parent window for dialog box.
|
||
// UINT uiFlags flags
|
||
// LPVOID pvIn input format (optional), only compressors that
|
||
// handle this format will be displayed.
|
||
// LPVOID pavi input stream for the options preview
|
||
// PCOMPVARS pcj returns COMPVARS struct for use with other APIs
|
||
// LPSTR lpszTitle Optional title for dialog box
|
||
//
|
||
// returns:
|
||
// TRUE if dialog shown and user chose a compressor.
|
||
// FALSE if dialog was not shown or user hit cancel.
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
BOOL VFWAPI ICCompressorChoose(
|
||
HWND hwnd, // parent window for dialog
|
||
UINT uiFlags, // flags
|
||
LPVOID pvIn, // input format (optional)
|
||
LPVOID pavi, // input stream (for preview - optional)
|
||
PCOMPVARS pcj, // state of compressor/dlg
|
||
LPSTR lpszTitle) // dialog title (if NULL, use default)
|
||
{
|
||
INT_PTR f;
|
||
PICCompressorChooseStuff p;
|
||
DWORD dwSize;
|
||
|
||
if (pcj == NULL || pcj->cbSize != sizeof(COMPVARS))
|
||
return FALSE;
|
||
|
||
//
|
||
// !!! Initialize the structure - unless the user has already done it
|
||
//
|
||
if (!(pcj->dwFlags & ICMF_COMPVARS_VALID)) {
|
||
pcj->hic = NULL;
|
||
pcj->fccType = 0;
|
||
pcj->fccHandler = 0;
|
||
pcj->lQ = ICQUALITY_DEFAULT;
|
||
pcj->lKey = -1; // means default
|
||
pcj->lDataRate = 300;
|
||
pcj->lpbiOut = NULL;
|
||
pcj->lpBitsOut = NULL;
|
||
pcj->lpBitsPrev = NULL;
|
||
pcj->dwFlags = 0;
|
||
pcj->lpState = NULL;
|
||
pcj->cbState = 0;
|
||
}
|
||
|
||
// Default type is a video compressor
|
||
if (pcj->fccType == 0)
|
||
pcj->fccType = ICTYPE_VIDEO;
|
||
|
||
p = (LPVOID)GlobalAllocPtr(GHND, sizeof(ICCompressorChooseStuff));
|
||
|
||
if (p == NULL)
|
||
return FALSE;
|
||
|
||
p->fccType = pcj->fccType;
|
||
p->fccHandler = pcj->fccHandler;
|
||
p->uiFlags = uiFlags;
|
||
p->pvIn = pvIn;
|
||
p->lQ = pcj->lQ;
|
||
p->lKey = pcj->lKey;
|
||
p->lDataRate = pcj->lDataRate;
|
||
p->lpszTitle = lpszTitle;
|
||
p->pavi = (PAVISTREAM)pavi;
|
||
p->hdd = NULL;
|
||
p->lpState = pcj->lpState;
|
||
pcj->lpState = NULL; // so it won't be freed
|
||
p->cbState = pcj->cbState;
|
||
// !!! Validate this pointer
|
||
// !!! AddRef if it is
|
||
if (p->pavi) {
|
||
if (p->pavi->lpVtbl->Info(p->pavi, &p->info, sizeof(p->info)) !=
|
||
AVIERR_OK || p->info.fccType != streamtypeVIDEO)
|
||
p->pavi = NULL;
|
||
}
|
||
|
||
f = DialogBoxParam(ghInst, TEXT("ICCDLG"),
|
||
hwnd, ICCompressorChooseDlgProc, (LPARAM)(LPVOID)p);
|
||
|
||
// !!! Treat error like cancel
|
||
if (f == -1)
|
||
f = FALSE;
|
||
|
||
//
|
||
// if the user picked a compressor then return this info to the caller
|
||
//
|
||
if (f) {
|
||
|
||
// If we are called twice in a row, we have good junk in here that
|
||
// needs to be freed before we tromp over it.
|
||
ICCompressorFree(pcj);
|
||
|
||
pcj->lQ = p->lQ;
|
||
pcj->lKey = p->lKey;
|
||
pcj->lDataRate = p->lDataRate;
|
||
pcj->hic = p->hic;
|
||
pcj->fccHandler = p->fccHandler;
|
||
pcj->lpState = p->lpState;
|
||
pcj->cbState = p->cbState;
|
||
|
||
pcj->dwFlags |= ICMF_COMPVARS_VALID;
|
||
}
|
||
|
||
GlobalFreePtr(p);
|
||
|
||
if (!f)
|
||
return FALSE;
|
||
|
||
if (pcj->hic && pvIn) { // hic is NULL if no compression selected
|
||
|
||
/* Get the format we're going to compress into. */
|
||
dwSize = ICCompressGetFormatSize(pcj->hic, pvIn);
|
||
if (!dwSize || ((pcj->lpbiOut =
|
||
(LPBITMAPINFO)GlobalAllocPtr(GMEM_MOVEABLE, dwSize)) == NULL)) {
|
||
ICClose(pcj->hic); // Close this since we're erroring
|
||
pcj->hic = NULL;
|
||
return FALSE;
|
||
}
|
||
ICCompressGetFormat(pcj->hic, pvIn, pcj->lpbiOut);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void SizeDialog(HWND hwnd, WORD id) {
|
||
RECT rc;
|
||
|
||
GetWindowRect(GetDlgItem(hwnd, id), &rc);
|
||
|
||
/* First, get rc in Client co-ords */
|
||
ScreenToClient(hwnd, (LPPOINT)&rc + 1);
|
||
rc.top = 0; rc.left = 0;
|
||
|
||
/* Grow by non-client size */
|
||
AdjustWindowRect(&rc, GetWindowLong(hwnd, GWL_STYLE),
|
||
GetMenu(hwnd) !=NULL);
|
||
|
||
/* That's the new size for the dialog */
|
||
SetWindowPos(hwnd, NULL, 0, 0, rc.right-rc.left,
|
||
rc.bottom-rc.top,
|
||
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||
}
|
||
|
||
|
||
void TermPreview(PICCompressorChooseStuff p)
|
||
{
|
||
if (p->hdd)
|
||
DrawDibClose(p->hdd);
|
||
p->hdd = NULL;
|
||
}
|
||
|
||
|
||
BOOL InitPreview(HWND hwnd, PICCompressorChooseStuff p) {
|
||
|
||
p->hdd = DrawDibOpen();
|
||
if (!p->hdd)
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#ifdef SAFETOYIELD
|
||
//
|
||
// Code to yield while we're not calling GetMessage.
|
||
// Dispatch all messages. Pressing ESC or closing aborts.
|
||
//
|
||
BOOL WinYield(HWND hwnd)
|
||
{
|
||
MSG msg;
|
||
BOOL fAbort=FALSE;
|
||
|
||
while(/* fWait > 0 && */ !fAbort && PeekMessage(&msg,NULL,0,0,PM_REMOVE))
|
||
{
|
||
if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
|
||
fAbort = TRUE;
|
||
if (msg.message == WM_SYSCOMMAND && (msg.wParam & 0xFFF0) == SC_CLOSE)
|
||
fAbort = TRUE;
|
||
|
||
if (msg.hwnd == hwnd) {
|
||
if (msg.message == WM_KEYDOWN ||
|
||
msg.message == WM_SYSKEYDOWN ||
|
||
msg.message == WM_HSCROLL ||
|
||
msg.message == WM_PARENTNOTIFY ||
|
||
msg.message == WM_LBUTTONDOWN) {
|
||
PostMessage(hwnd, msg.message, msg.wParam, msg.lParam);
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
TranslateMessage(&msg);
|
||
DispatchMessage(&msg);
|
||
}
|
||
return fAbort;
|
||
}
|
||
#endif
|
||
|
||
LONG CALLBACK _loadds PreviewStatusProc(LPARAM lParam, UINT message, LONG l)
|
||
{
|
||
TCHAR ach[100], achT[100];
|
||
BOOL f;
|
||
PICCompressorChooseStuff p = (PICCompressorChooseStuff) lParam;
|
||
|
||
if (message != ICSTATUS_STATUS) {
|
||
DPF(("Status callback: lParam = %lx, message = %u, l = %lu\n", lParam, message, l));
|
||
}
|
||
|
||
// !!!!
|
||
// !!!! Status messages need to be fixed!!!!!!
|
||
// !!!!
|
||
|
||
switch (message) {
|
||
case ICSTATUS_START:
|
||
break;
|
||
|
||
case ICSTATUS_STATUS:
|
||
LoadString (ghInst, ID_FRAMECOMPRESSING, achT, NUMELMS(achT));
|
||
wsprintf(ach, achT, GetScrollPos(GetDlgItem(p->hwnd,
|
||
ID_PREVIEWSCROLL), SB_CTL), l);
|
||
|
||
SetDlgItemText(p->hwnd, ID_PREVIEWTEXT, ach);
|
||
break;
|
||
|
||
case ICSTATUS_END:
|
||
break;
|
||
|
||
case ICSTATUS_YIELD:
|
||
|
||
break;
|
||
}
|
||
|
||
#ifdef SAFETOYIELD
|
||
f = WinYield(p->hwnd);
|
||
#else
|
||
f = FALSE;
|
||
#endif
|
||
|
||
if (f) {
|
||
DPF(("Aborting from within status proc!\n"));
|
||
}
|
||
|
||
return f;
|
||
}
|
||
|
||
|
||
void Preview(HWND hwnd, PICCompressorChooseStuff p, BOOL fCompress)
|
||
{
|
||
RECT rc;
|
||
HDC hdc;
|
||
int pos;
|
||
HANDLE h;
|
||
HCURSOR hcur = NULL;
|
||
LPBITMAPINFOHEADER lpbi, lpbiU, lpbiC = NULL;
|
||
TCHAR ach[120], achT[100];
|
||
LONG lsizeD = 0;
|
||
LONG lSize;
|
||
int x;
|
||
|
||
// Not previewing right now!
|
||
if (!p->hdd || !p->pgf)
|
||
return;
|
||
|
||
pos = GetScrollPos(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL);
|
||
lpbi = lpbiU = AVIStreamGetFrame(p->pgf, pos);
|
||
if (!lpbi)
|
||
return;
|
||
|
||
//
|
||
// What would the image look like compressed?
|
||
//
|
||
if (fCompress && ((INT_PTR)p->hic > 0)) {
|
||
LRESULT lRet;
|
||
|
||
lRet = (LRESULT)ICSetStatusProc(p->hic, 0, (LPARAM)p, PreviewStatusProc);
|
||
if (lRet != 0) {
|
||
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
||
}
|
||
|
||
// !!! Gives whole data rate to this stream
|
||
// !!! What to do if Rate or Scale is zero?
|
||
lSize = (GetDlgItemInt(hwnd, ID_DATARATE, NULL, FALSE) * 1024L) /
|
||
((p->info.dwScale && p->info.dwRate) ?
|
||
(p->info.dwRate / p->info.dwScale) : 1L);
|
||
h = ICImageCompress(p->hic,
|
||
0,
|
||
(LPBITMAPINFO)lpbi,
|
||
(LPBYTE)lpbi + lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD),
|
||
NULL,
|
||
GetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL) * 100,
|
||
&lSize);
|
||
if (hcur)
|
||
SetCursor(hcur);
|
||
if (h)
|
||
lpbiC = (LPBITMAPINFOHEADER)GlobalLock(h);
|
||
// Use the compressed image if we have one.. else use the original frame
|
||
if (lpbiC)
|
||
lpbi = lpbiC;
|
||
}
|
||
|
||
//
|
||
// If we chose NO COMPRESSION, tell them the size of the data as its
|
||
// compressed now. Otherwise, use the size it will become when compressed
|
||
// or the full frame size.
|
||
//
|
||
if (fCompress && (p->hic == 0)) {
|
||
p->pavi->lpVtbl->Read(p->pavi, pos, 1, NULL, 0, &lsizeD, NULL);
|
||
} else {
|
||
lsizeD = (lpbiC ? lpbiC->biSizeImage : lpbiU->biSizeImage);
|
||
}
|
||
|
||
hdc = GetDC(GetDlgItem(hwnd, ID_PREVIEWWIN));
|
||
GetClientRect(GetDlgItem(hwnd, ID_PREVIEWWIN), &rc);
|
||
|
||
// Clip regions aren't set up right for windows in a dialog, so make sure
|
||
// we'll only paint into the window and not spill around it.
|
||
IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
|
||
|
||
// Now go ahead and draw a miniature frame that preserves the aspect ratio
|
||
// centred in our preview window
|
||
x = MulDiv((int)lpbi->biWidth, 3, 4);
|
||
if (x <= (int)lpbi->biHeight) {
|
||
rc.left = (rc.right - MulDiv(rc.right, x, (int)lpbi->biHeight)) / 2;
|
||
rc.right -= rc.left;
|
||
} else {
|
||
x = MulDiv((int)lpbi->biHeight, 4, 3);
|
||
rc.top = (rc.bottom - MulDiv(rc.bottom, x, (int)lpbi->biWidth)) / 2;
|
||
rc.bottom -= rc.top;
|
||
}
|
||
DrawDibDraw(p->hdd, hdc, rc.left, rc.top, rc.right - rc.left,
|
||
rc.bottom - rc.top, lpbi, NULL, 0, 0, -1, -1, 0);
|
||
|
||
// Print the sizes and ratio for this frame
|
||
LoadString (ghInst, ID_FRAMESIZE, achT, NUMELMS(achT));
|
||
wsprintf(ach, achT,
|
||
GetScrollPos(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL),
|
||
lsizeD,
|
||
lpbiU->biSizeImage,
|
||
lsizeD * 100 / lpbiU->biSizeImage);
|
||
SetDlgItemText(hwnd, ID_PREVIEWTEXT, ach);
|
||
if (lpbiC)
|
||
GlobalFreePtr(lpbiC);
|
||
ReleaseDC(GetDlgItem(hwnd, ID_PREVIEWWIN), hdc);
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// ICCompressorChooseDlgProc
|
||
//
|
||
// dialog box procedure for ICCompressorChoose, a pointer to a
|
||
// ICCompressorChooseStuff pointer must be passed to initialize this
|
||
// dialog.
|
||
//
|
||
// NOTE: this dialog box procedure does not use any globals
|
||
// so I did not bother to _export it or use MakeProcAddress() if
|
||
// you change this code to use globals, etc, be aware of this fact.
|
||
//
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
#ifdef _WIN32
|
||
// THIS IS A HACK. We need to store the HIC for each item in a combo
|
||
// box. We also need to store it's index. On NT these two items cannot
|
||
// be stored in a DWORD. Hence use a static array to contain the HIC
|
||
// elements which can then be referenced by the stored index.
|
||
// Look at the GetItemData and SetItemData routines.
|
||
|
||
#define MAX_COMPRESSORS 100
|
||
HIC aHic[MAX_COMPRESSORS]; // Hopefully, noone will have more than this
|
||
|
||
HIC GetHIC(HWND hwndCB, int index)
|
||
{
|
||
index = (int) ComboBox_GetItemData(hwndCB,index);
|
||
if (index>0 && index < MAX_COMPRESSORS) {
|
||
return(aHic[index]);
|
||
} else {
|
||
return((HIC)-1);
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
#define GetHIC(hwnd,index) ((HIC)LOWORD(ComboBox_GetItemData((hwnd),(index))))
|
||
|
||
#endif
|
||
|
||
INT_PTR VFWAPI ICCompressorChooseDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
int i,n;
|
||
int pos;
|
||
HWND hwndC;
|
||
PICCompressorChooseStuff p;
|
||
HIC hic;
|
||
BOOL fConfig, fAbout, fQuality, fKey, fDataRate;
|
||
BOOL fShowKeyFrame, fShowDataRate, fShowPreview;
|
||
int nSelectMe = -1;
|
||
TCHAR ach[128], achT[80];
|
||
RECT rc;
|
||
UINT id;
|
||
HDC hdc;
|
||
BOOL f = FALSE, fCanDecompress = FALSE;
|
||
LONG lsize;
|
||
LPBITMAPINFOHEADER lpbi = NULL;
|
||
BOOL fStreamIsCompressed = FALSE;
|
||
HRESULT hr;
|
||
|
||
p = (PICCompressorChooseStuff)GetWindowLongPtr(hwnd,DWLP_USER);
|
||
|
||
switch (msg)
|
||
{
|
||
case WM_INITDIALOG:
|
||
#define but &&
|
||
#define and &&
|
||
#define is ==
|
||
#define isnt !=
|
||
|
||
if (lParam == 0)
|
||
return FALSE;
|
||
|
||
SetWindowLongPtr(hwnd,DWLP_USER,lParam);
|
||
p = (PICCompressorChooseStuff)lParam;
|
||
|
||
p->hwnd = hwnd;
|
||
|
||
// Let the user change the title of the dialog
|
||
if (p->lpszTitle != NULL)
|
||
SetWindowTextA(hwnd, p->lpszTitle);
|
||
|
||
#ifdef _WIN32
|
||
havifile = GetModuleHandleA("avifil32");
|
||
#else
|
||
havifile = GetModuleHandleA("avifile");
|
||
#endif
|
||
|
||
if (havifile) {
|
||
(FARPROC)AVIStreamGetFrameOpen =
|
||
GetProcAddress((HINSTANCE)havifile,
|
||
(LPCSTR)"AVIStreamGetFrameOpen");
|
||
(FARPROC)AVIStreamGetFrame =
|
||
GetProcAddress((HINSTANCE)havifile,
|
||
(LPCSTR)"AVIStreamGetFrame");
|
||
(FARPROC)AVIStreamGetFrameClose =
|
||
GetProcAddress((HINSTANCE)havifile,
|
||
(LPCSTR)"AVIStreamGetFrameClose");
|
||
if (p->pavi)
|
||
p->pgf = AVIStreamGetFrameOpen(p->pavi, NULL);
|
||
}
|
||
|
||
// We weren't passed in an input format but we have a PAVI we
|
||
// can get a format from
|
||
if (p->pvIn is NULL but p->pavi isnt NULL and p->pgf isnt NULL) {
|
||
|
||
// We need to nuke pvIn later
|
||
f = TRUE;
|
||
|
||
// Find out if the AVI Stream is compressed or not
|
||
p->pavi->lpVtbl->ReadFormat(p->pavi, 0, NULL, &lsize);
|
||
if (lsize)
|
||
lpbi = (LPBITMAPINFOHEADER)GlobalAllocPtr(GMEM_MOVEABLE,
|
||
lsize);
|
||
if (lpbi) {
|
||
hr = p->pavi->lpVtbl->ReadFormat(p->pavi, 0, lpbi, &lsize);
|
||
if (hr == AVIERR_OK)
|
||
fStreamIsCompressed = lpbi->biCompression != BI_RGB;
|
||
GlobalFreePtr(lpbi);
|
||
}
|
||
|
||
// Get the decompressed format of the AVI stream
|
||
lpbi = AVIStreamGetFrame(p->pgf, 0);
|
||
if (lpbi) {
|
||
lsize = lpbi->biSize +
|
||
lpbi->biClrUsed * sizeof(PALETTEENTRY);
|
||
p->pvIn = (LPBITMAPINFOHEADER)GlobalAllocPtr(GMEM_MOVEABLE,
|
||
lsize);
|
||
if (p->pvIn)
|
||
hmemcpy(p->pvIn, lpbi, lsize);
|
||
}
|
||
}
|
||
|
||
//
|
||
// now fill the combo box with all compressors
|
||
//
|
||
hwndC = GetDlgItem(hwnd, ID_COMPRESSOR);
|
||
|
||
for (i=0; ICInfo(p->fccType, i, &p->icinfo); i++)
|
||
{
|
||
hic = ICOpen(p->icinfo.fccType, p->icinfo.fccHandler,
|
||
ICMODE_COMPRESS);
|
||
|
||
if (hic)
|
||
{
|
||
//
|
||
// skip this compressor if it can't handle the
|
||
// specifed format and we want to skip such compressors
|
||
//
|
||
if (!(p->uiFlags & ICMF_CHOOSE_ALLCOMPRESSORS) &&
|
||
p->pvIn != NULL &&
|
||
ICCompressQuery(hic, p->pvIn, NULL) != ICERR_OK)
|
||
{
|
||
ICClose(hic);
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// find out the compressor name.
|
||
//
|
||
ICGetInfo(hic, &p->icinfo, sizeof(p->icinfo));
|
||
|
||
//
|
||
// stuff it into the combo box and remember which one it was
|
||
//
|
||
#if defined _WIN32 && !defined UNICODE
|
||
//assert (NUMELMS(ach) >= NUMELMS(p->icinfo.szDescription));
|
||
mmWideToAnsi (ach, p->icinfo.szDescription,
|
||
NUMELMS(p->icinfo.szDescription));
|
||
n = ComboBox_AddString(hwndC, ach);
|
||
#else
|
||
n = ComboBox_AddString(hwndC, p->icinfo.szDescription);
|
||
#endif
|
||
|
||
#ifdef _WIN32
|
||
// Making a LONG out of a hic and an int just won't cut it
|
||
// We have to use some auxiliary storage
|
||
if (i >= MAX_COMPRESSORS) {
|
||
#ifdef DEBUG
|
||
UINT n = fDebug;
|
||
fDebug = 1;
|
||
DPF(("Overwriting array...i==%d\n",i));
|
||
DebugBreak();
|
||
fDebug = n;
|
||
#endif
|
||
}
|
||
aHic[i] = hic;
|
||
ComboBox_SetItemData(hwndC, n, i);
|
||
#else
|
||
ComboBox_SetItemData(hwndC, n, MAKELONG(hic, i));
|
||
#endif
|
||
|
||
// This compressor is the one we want to come up default ?
|
||
// Set its state
|
||
// !!! Combo Box better not be sorted!
|
||
// Convert both to upper case for an insensitive compare
|
||
AnsiUpperBuff((LPSTR)&p->icinfo.fccHandler, sizeof(FOURCC));
|
||
AnsiUpperBuff((LPSTR)&p->fccHandler, sizeof(FOURCC));
|
||
if (p->icinfo.fccHandler == p->fccHandler) {
|
||
nSelectMe = n;
|
||
if (p->lpState)
|
||
ICSetState(hic, p->lpState, p->cbState);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Next add a "No Recompression" item unless they passed in an
|
||
// uncompressed format
|
||
//
|
||
if (fStreamIsCompressed || (p->pvIn &&
|
||
((LPBITMAPINFOHEADER)p->pvIn)->biCompression != BI_RGB)) {
|
||
LoadString (ghInst, ID_NOCOMPSTRING, ach, NUMELMS(ach));
|
||
n = ComboBox_AddString(hwndC, ach);
|
||
#ifdef _WIN32
|
||
aHic[MAX_COMPRESSORS - 1] = 0;
|
||
ComboBox_SetItemData(hwndC, n, MAX_COMPRESSORS - 1);
|
||
#else
|
||
ComboBox_SetItemData(hwndC, n, 0);
|
||
#endif
|
||
// Select "No Recompression" as the default if that was the one
|
||
// last chosen. This will also be the default choice (0).
|
||
if (p->fccHandler == 0)
|
||
nSelectMe = n;
|
||
}
|
||
//
|
||
// Now add a "Full Frames (Uncompressed)" item unless we can't
|
||
// decompress this format and they don't want all choices anyway
|
||
//
|
||
if (!(p->uiFlags & ICMF_CHOOSE_ALLCOMPRESSORS) && p->pvIn) {
|
||
// If it's RGB, of course, just offer the option.
|
||
if (((LPBITMAPINFOHEADER)p->pvIn)->biCompression != BI_RGB) {
|
||
if ((hic = ICLocate(ICTYPE_VIDEO, 0, p->pvIn, NULL,
|
||
ICMODE_DECOMPRESS)) == NULL)
|
||
goto SkipFF;
|
||
else
|
||
ICClose(hic);
|
||
}
|
||
}
|
||
|
||
LoadString (ghInst, ID_FULLFRAMESSTRING, ach, NUMELMS(ach));
|
||
n = ComboBox_AddString(hwndC, ach);
|
||
#ifdef _WIN32
|
||
aHic[MAX_COMPRESSORS - 2] = (HIC)-1;
|
||
ComboBox_SetItemData(hwndC, n, MAX_COMPRESSORS - 2);
|
||
#else
|
||
ComboBox_SetItemData(hwndC, n, MAKELONG(-1, 0));
|
||
#endif
|
||
|
||
// Select "Full Frames" if that was the last one chosen
|
||
// !!! Combo Box better not be sorted!
|
||
if (p->fccHandler == comptypeDIB)
|
||
nSelectMe = n;
|
||
fCanDecompress = TRUE;
|
||
|
||
SkipFF:
|
||
// If we haven't selected anything yet, choose something at random.
|
||
if (nSelectMe == -1)
|
||
nSelectMe = 0;
|
||
|
||
fShowKeyFrame = p->uiFlags & ICMF_CHOOSE_KEYFRAME;
|
||
fShowDataRate = p->uiFlags & ICMF_CHOOSE_DATARATE;
|
||
// Don't show a preview if we can't draw it!
|
||
fShowPreview = (p->uiFlags & ICMF_CHOOSE_PREVIEW) && p->pavi &&
|
||
fCanDecompress;
|
||
|
||
// Hide our secret small place holders
|
||
ShowWindow(GetDlgItem(hwnd, ID_CHOOSE_SMALL), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_CHOOSE_NORMAL), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_CHOOSE_BIG), SW_HIDE);
|
||
|
||
if (!fShowKeyFrame) {
|
||
ShowWindow(GetDlgItem(hwnd, ID_KEYFRAME), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_KEYFRAMEBOX), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_KEYFRAMETEXT), SW_HIDE);
|
||
}
|
||
|
||
if (!fShowDataRate) {
|
||
ShowWindow(GetDlgItem(hwnd, ID_DATARATE), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_DATARATEBOX), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_DATARATETEXT), SW_HIDE);
|
||
}
|
||
|
||
if (!fShowPreview) {
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEW), SW_HIDE);
|
||
}
|
||
|
||
// We start without these
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEWWIN), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEWTEXT), SW_HIDE);
|
||
|
||
//
|
||
// What size dialog do we need?
|
||
//
|
||
if (!fShowPreview && (!fShowDataRate || !fShowKeyFrame))
|
||
SizeDialog(hwnd, ID_CHOOSE_SMALL);
|
||
else
|
||
SizeDialog(hwnd, ID_CHOOSE_NORMAL);
|
||
|
||
//
|
||
// Swap places for KeyFrameEvery and DataRate
|
||
//
|
||
if (fShowDataRate && !fShowKeyFrame) {
|
||
GetWindowRect(GetDlgItem(hwnd, ID_KEYFRAME), &rc);
|
||
ScreenToClient(hwnd, (LPPOINT)&rc);
|
||
ScreenToClient(hwnd, (LPPOINT)&rc + 1);
|
||
MoveWindow(GetDlgItem(hwnd, ID_DATARATE), rc.left, rc.top,
|
||
rc.right - rc.left, rc.bottom - rc.top, FALSE);
|
||
GetWindowRect(GetDlgItem(hwnd, ID_KEYFRAMEBOX), &rc);
|
||
ScreenToClient(hwnd, (LPPOINT)&rc);
|
||
ScreenToClient(hwnd, (LPPOINT)&rc + 1);
|
||
MoveWindow(GetDlgItem(hwnd, ID_DATARATEBOX), rc.left, rc.top,
|
||
rc.right - rc.left, rc.bottom - rc.top, FALSE);
|
||
GetWindowRect(GetDlgItem(hwnd, ID_KEYFRAMETEXT), &rc);
|
||
ScreenToClient(hwnd, (LPPOINT)&rc);
|
||
ScreenToClient(hwnd, (LPPOINT)&rc + 1);
|
||
MoveWindow(GetDlgItem(hwnd, ID_DATARATETEXT), rc.left, rc.top,
|
||
rc.right - rc.left, rc.bottom - rc.top, TRUE);
|
||
}
|
||
|
||
//
|
||
// Restore the dlg to the settings found in the structure
|
||
//
|
||
SetScrollRange(GetDlgItem(hwnd, ID_QUALITY), SB_CTL, 0, 100, FALSE);
|
||
CheckDlgButton(hwnd, ID_KEYFRAMEBOX, (BOOL)(p->lKey != 0));
|
||
EnableWindow(GetDlgItem(hwnd, ID_KEYFRAME), (BOOL)(p->lKey != 0));
|
||
CheckDlgButton(hwnd, ID_DATARATEBOX, (BOOL)(p->lDataRate));
|
||
EnableWindow(GetDlgItem(hwnd, ID_DATARATE), (BOOL)(p->lDataRate));
|
||
if (p->lKey == -1) // we haven't chosen a key frame yet. Later
|
||
// we'll choose the compressor's default.
|
||
SetDlgItemInt(hwnd, ID_KEYFRAME, 0, FALSE);
|
||
else
|
||
SetDlgItemInt(hwnd, ID_KEYFRAME, (int)p->lKey, FALSE);
|
||
SetDlgItemInt(hwnd, ID_DATARATE, (int)p->lDataRate, FALSE);
|
||
ComboBox_SetCurSel(GetDlgItem(hwnd, ID_COMPRESSOR), nSelectMe);
|
||
SendMessage(hwnd, WM_COMMAND,
|
||
GET_WM_COMMAND_MPS(ID_COMPRESSOR, hwndC, CBN_SELCHANGE));
|
||
|
||
// We alloced this ourselves and need to free it now
|
||
if (f && p->pvIn)
|
||
GlobalFreePtr(p->pvIn);
|
||
|
||
return TRUE;
|
||
|
||
case WM_PALETTECHANGED:
|
||
|
||
// It came from us. Ignore it
|
||
if ((HWND)wParam == hwnd)
|
||
break;
|
||
|
||
case WM_QUERYNEWPALETTE:
|
||
|
||
if (!p->hdd)
|
||
break;
|
||
|
||
hdc = GetDC(hwnd);
|
||
|
||
//
|
||
// Realize the palette of the first video stream
|
||
// !!! If first stream isn't video, we're DEAD!
|
||
//
|
||
if (f = DrawDibRealize(p->hdd, hdc, FALSE))
|
||
InvalidateRect(hwnd, NULL, FALSE);
|
||
|
||
ReleaseDC(hwnd, hdc);
|
||
|
||
return f;
|
||
|
||
case WM_PAINT:
|
||
if (!p->hdd)
|
||
break;
|
||
// Paint everybody else before the Preview window since that'll
|
||
// take awhile, and we don't want an ugly window during it.
|
||
DefWindowProc(hwnd, msg, wParam, lParam);
|
||
UpdateWindow(hwnd);
|
||
Preview(hwnd, p, TRUE);
|
||
return 0;
|
||
|
||
case WM_HSCROLL:
|
||
#ifdef _WIN32
|
||
id = GetWindowLong(GET_WM_HSCROLL_HWND(wParam, lParam), GWL_ID);
|
||
pos = GetScrollPos(GET_WM_HSCROLL_HWND(wParam, lParam), SB_CTL);
|
||
#else
|
||
id = GetWindowWord((HWND)HIWORD(lParam), GWW_ID);
|
||
pos = GetScrollPos((HWND)HIWORD(lParam), SB_CTL);
|
||
#endif
|
||
|
||
switch (GET_WM_HSCROLL_CODE(wParam, lParam))
|
||
{
|
||
case SB_LINEDOWN: pos += 1; break;
|
||
case SB_LINEUP: pos -= 1; break;
|
||
case SB_PAGEDOWN: pos += (id == ID_QUALITY) ? 10 :
|
||
(int)p->info.dwLength / 10; break;
|
||
case SB_PAGEUP: pos -= (id == ID_QUALITY) ? 10 :
|
||
(int)p->info.dwLength / 10; break;
|
||
case SB_THUMBTRACK:
|
||
case SB_THUMBPOSITION: pos = GET_WM_HSCROLL_POS(wParam, lParam); break;
|
||
case SB_ENDSCROLL:
|
||
Preview(hwnd, p, TRUE); // Draw this compressed frame
|
||
return TRUE; // don't fall through and invalidate
|
||
default:
|
||
return TRUE;
|
||
}
|
||
|
||
if (id == ID_QUALITY) {
|
||
if (pos < 0)
|
||
pos = 0;
|
||
if (pos > (ICQUALITY_HIGH/100))
|
||
pos = (ICQUALITY_HIGH/100);
|
||
SetDlgItemInt(hwnd, ID_QUALITYTEXT, pos, FALSE);
|
||
SetScrollPos(GET_WM_HSCROLL_HWND(wParam, lParam), SB_CTL, pos, TRUE);
|
||
|
||
} else if (id == ID_PREVIEWSCROLL) {
|
||
|
||
// !!! round off !!!
|
||
if (pos < (int)p->info.dwStart)
|
||
pos = (int)p->info.dwStart;
|
||
if (pos >= (int)p->info.dwStart + (int)p->info.dwLength)
|
||
pos = (int)(p->info.dwStart + p->info.dwLength - 1);
|
||
SetScrollPos(GET_WM_HSCROLL_HWND(wParam, lParam), SB_CTL, pos, TRUE);
|
||
|
||
LoadString (ghInst, ID_FRAME, achT, NUMELMS(achT));
|
||
wsprintf(ach, achT, pos);
|
||
SetDlgItemText(hwnd, ID_PREVIEWTEXT, ach);
|
||
|
||
//Drawing while scrolling flashes palettes because they aren't
|
||
//compressed.
|
||
//Preview(hwnd, p, FALSE);
|
||
}
|
||
|
||
break;
|
||
|
||
case WM_COMMAND:
|
||
hwndC = GetDlgItem(hwnd, ID_COMPRESSOR);
|
||
n = ComboBox_GetCurSel(hwndC);
|
||
#ifdef _WIN32
|
||
hic = (n == -1) ? NULL
|
||
: aHic[ComboBox_GetItemData(hwndC,n)];
|
||
#else
|
||
hic = (n == -1) ? NULL : (HIC)LOWORD(ComboBox_GetItemData(hwndC,n));
|
||
#endif
|
||
if (!p->fClosing)
|
||
p->hic = hic;
|
||
|
||
switch ((int)GET_WM_COMMAND_ID(wParam, lParam))
|
||
{
|
||
// When data rate box loses focus, update our preview
|
||
case ID_DATARATE:
|
||
if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_KILLFOCUS)
|
||
Preview(hwnd, p, TRUE);
|
||
break;
|
||
|
||
// Enable the "data rate" edit box iff we've checked it
|
||
case ID_DATARATEBOX:
|
||
f = IsDlgButtonChecked(hwnd, ID_DATARATEBOX);
|
||
EnableWindow(GetDlgItem(hwnd, ID_DATARATE), f);
|
||
break;
|
||
|
||
// Enable the "key frame" edit box iff we've checked it
|
||
case ID_KEYFRAMEBOX:
|
||
f = IsDlgButtonChecked(hwnd, ID_KEYFRAMEBOX);
|
||
EnableWindow(GetDlgItem(hwnd, ID_KEYFRAME), f);
|
||
break;
|
||
|
||
case ID_COMPRESSOR:
|
||
if (GET_WM_COMMAND_CMD(wParam, lParam) != CBN_SELCHANGE)
|
||
break;
|
||
|
||
if ((INT_PTR)p->hic > 0) {
|
||
ICGetInfo(p->hic, &p->icinfo, sizeof(p->icinfo));
|
||
|
||
fConfig = (BOOL)ICQueryConfigure(p->hic);
|
||
fAbout = ICQueryAbout(p->hic);
|
||
fQuality = (p->icinfo.dwFlags & VIDCF_QUALITY) != 0;
|
||
fKey = (p->icinfo.dwFlags & VIDCF_TEMPORAL) != 0;
|
||
// if they do quality we fake crunch
|
||
fDataRate= (p->icinfo.dwFlags &
|
||
(VIDCF_QUALITY|VIDCF_CRUNCH)) != 0;
|
||
// We haven't chosen a key frame rate yet. Use this
|
||
// compressor's default.
|
||
if (p->lKey == -1)
|
||
SetDlgItemInt(hwnd, ID_KEYFRAME,
|
||
(int)ICGetDefaultKeyFrameRate(p->hic), FALSE);
|
||
} else {
|
||
fConfig = fAbout = fQuality = fKey = fDataRate = FALSE;
|
||
}
|
||
|
||
EnableWindow(GetDlgItem(hwnd, ID_CONFIG), fConfig);
|
||
EnableWindow(GetDlgItem(hwnd, ID_ABOUT), fAbout);
|
||
EnableWindow(GetDlgItem(hwnd, ID_QUALITY), fQuality);
|
||
EnableWindow(GetDlgItem(hwnd, ID_QUALITYLABEL), fQuality);
|
||
EnableWindow(GetDlgItem(hwnd, ID_QUALITYTEXT), fQuality);
|
||
EnableWindow(GetDlgItem(hwnd, ID_KEYFRAMEBOX), fKey);
|
||
EnableWindow(GetDlgItem(hwnd, ID_KEYFRAME),
|
||
fKey && IsDlgButtonChecked(hwnd, ID_KEYFRAMEBOX));
|
||
EnableWindow(GetDlgItem(hwnd, ID_KEYFRAMETEXT), fKey);
|
||
EnableWindow(GetDlgItem(hwnd, ID_DATARATEBOX), fDataRate);
|
||
EnableWindow(GetDlgItem(hwnd, ID_DATARATE),
|
||
fDataRate && IsDlgButtonChecked(hwnd, ID_DATARATEBOX));
|
||
EnableWindow(GetDlgItem(hwnd, ID_DATARATETEXT), fDataRate);
|
||
|
||
if (fQuality)
|
||
{
|
||
if (p->lQ == ICQUALITY_DEFAULT && (INT_PTR)p->hic > 0)
|
||
{
|
||
SetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL,
|
||
(int)ICGetDefaultQuality(p->hic) / 100, TRUE);
|
||
}
|
||
else
|
||
{
|
||
SetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL,
|
||
(int)p->lQ / 100, TRUE);
|
||
}
|
||
|
||
pos = GetScrollPos(GetDlgItem(hwnd, ID_QUALITY),SB_CTL);
|
||
SetDlgItemInt(hwnd, ID_QUALITYTEXT, pos, FALSE);
|
||
}
|
||
|
||
// redraw with new compressor
|
||
Preview(hwnd, p, TRUE);
|
||
|
||
break;
|
||
|
||
case ID_CONFIG:
|
||
if ((INT_PTR)p->hic > 0) {
|
||
ICConfigure(p->hic, hwnd);
|
||
Preview(hwnd, p, TRUE);
|
||
}
|
||
break;
|
||
|
||
case ID_ABOUT:
|
||
if ((INT_PTR)p->hic > 0)
|
||
ICAbout(p->hic, hwnd);
|
||
break;
|
||
|
||
case ID_PREVIEW:
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEW), SW_HIDE);
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEWWIN), SW_SHOW);
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SW_SHOW);
|
||
ShowWindow(GetDlgItem(hwnd, ID_PREVIEWTEXT), SW_SHOW);
|
||
SizeDialog(hwnd, ID_CHOOSE_BIG);
|
||
// !!! truncation
|
||
SetScrollRange(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL,
|
||
(int)p->info.dwStart,
|
||
(int)(p->info.dwStart + p->info.dwLength - 1),
|
||
FALSE);
|
||
SetScrollPos(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL,
|
||
(int)p->info.dwStart, TRUE);
|
||
LoadString (ghInst, ID_FRAME, achT, NUMELMS(achT));
|
||
wsprintf(ach, achT, p->info.dwStart);
|
||
SetDlgItemText(hwnd, ID_PREVIEWTEXT, ach);
|
||
InitPreview(hwnd, p);
|
||
break;
|
||
|
||
case IDOK:
|
||
|
||
// !!! We need to call ICInfo to get the FOURCC used
|
||
// in system.ini. Calling ICGetInfo will return the
|
||
// FOURCC the compressor thinks it is, which won't
|
||
// work.
|
||
// Get the HIWORD before we nuke it.
|
||
#ifndef _WIN32
|
||
i = HIWORD(ComboBox_GetItemData(hwndC, n));
|
||
|
||
//
|
||
// Don't close the current compressor in our CANCEL loop
|
||
//
|
||
ComboBox_SetItemData(hwndC, n, 0);
|
||
#else
|
||
i = (int) ComboBox_GetItemData(hwndC, n);
|
||
aHic[i] = 0;
|
||
#endif
|
||
|
||
//
|
||
// Return the values of the dlg to the caller
|
||
//
|
||
p->hic = hic;
|
||
|
||
p->lQ = 100 *
|
||
GetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL);
|
||
|
||
if (IsDlgButtonChecked(hwnd, ID_KEYFRAMEBOX))
|
||
p->lKey = GetDlgItemInt(hwnd, ID_KEYFRAME, NULL, FALSE);
|
||
else
|
||
p->lKey = 0;
|
||
|
||
if (IsDlgButtonChecked(hwnd, ID_DATARATEBOX))
|
||
p->lDataRate = GetDlgItemInt(hwnd, ID_DATARATE, NULL,
|
||
FALSE);
|
||
else
|
||
p->lDataRate = 0;
|
||
|
||
// We've chosen a valid compressor. Do stuff.
|
||
if ((INT_PTR)p->hic > 0) {
|
||
|
||
// !!! We need to call ICInfo to get the FOURCC used
|
||
// in system.ini. Calling ICGetInfo will return the
|
||
// FOURCC the compressor thinks it is, which won't
|
||
// work.
|
||
ICInfo(p->fccType, i, &p->icinfo);
|
||
p->fccHandler = p->icinfo.fccHandler; // identify it
|
||
|
||
// Free the old state
|
||
if (p->lpState) {
|
||
GlobalFreePtr(p->lpState);
|
||
p->lpState = NULL;
|
||
}
|
||
// Get the new state
|
||
p->cbState = ICGetStateSize(p->hic);
|
||
if (p->cbState) { // Remember it's config state
|
||
p->lpState = GlobalAllocPtr(GMEM_MOVEABLE,
|
||
p->cbState);
|
||
if (p->lpState) {
|
||
ICGetState(p->hic, p->lpState, p->cbState);
|
||
}
|
||
}
|
||
} else if ((INT_PTR)p->hic == -1) { // "Full Frames"
|
||
p->fccHandler = comptypeDIB;
|
||
p->hic = 0;
|
||
} else { // "No Compression"
|
||
p->fccHandler = 0L;
|
||
p->hic = 0;
|
||
}
|
||
|
||
// fall through
|
||
|
||
case IDCANCEL:
|
||
p->fClosing = TRUE;
|
||
|
||
if (GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL)
|
||
p->hic = NULL;
|
||
|
||
n = ComboBox_GetCount(hwndC);
|
||
for (i=0; i<n; i++)
|
||
{
|
||
#ifdef _WIN32
|
||
hic = (HIC) aHic[ComboBox_GetItemData(hwndC, i)];
|
||
#else
|
||
hic = (HIC) LOWORD(ComboBox_GetItemData(hwndC,i));
|
||
#endif
|
||
if ((INT_PTR)hic > 0) {
|
||
ICClose(hic);
|
||
}
|
||
}
|
||
|
||
TermPreview(p);
|
||
if (p->pgf)
|
||
AVIStreamGetFrameClose(p->pgf);
|
||
p->pgf = NULL;
|
||
EndDialog(hwnd, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* dprintf() is called by the DPF macro if DEBUG is defined at compile time.
|
||
*
|
||
* The messages will be send to COM1: like any debug message. To
|
||
* enable debug output, add the following to WIN.INI :
|
||
*
|
||
* [debug]
|
||
* ICM=1
|
||
*
|
||
****************************************************************************/
|
||
|
||
#ifdef DEBUG
|
||
|
||
|
||
#define MODNAME "ICM"
|
||
extern char szDebug[]; // in MSVIDEO
|
||
|
||
static void cdecl dprintf(LPSTR szFormat, ...)
|
||
{
|
||
char ach[128];
|
||
|
||
#ifdef _WIN32
|
||
va_list va;
|
||
if (fDebug == -1)
|
||
fDebug = mmGetProfileIntA(szDebug,MODNAME, FALSE);
|
||
|
||
if (!fDebug)
|
||
return;
|
||
|
||
va_start(va, szFormat);
|
||
if (szFormat[0] == '!')
|
||
ach[0]=0, szFormat++;
|
||
else
|
||
wsprintfA(ach, MODNAME ": (tid %x) ", GetCurrentThreadId());
|
||
|
||
wvsprintfA(ach+lstrlenA(ach),szFormat,va);
|
||
va_end(va);
|
||
// lstrcat(ach, "\r\r\n");
|
||
#else
|
||
if (fDebug == -1)
|
||
fDebug = GetProfileInt("Debug",MODNAME, FALSE);
|
||
|
||
if (!fDebug)
|
||
return;
|
||
|
||
if (szFormat[0] == '!')
|
||
ach[0]=0, szFormat++;
|
||
else
|
||
lstrcpy(ach, MODNAME ": ");
|
||
|
||
wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
|
||
// lstrcat(ach, "\r\r\n");
|
||
#endif
|
||
|
||
OutputDebugStringA(ach);
|
||
}
|
||
|
||
#endif
|
||
|
||
|