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

563 lines
18 KiB
C
Raw Blame History

This file contains invisible Unicode characters

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

/****************************************************************************
*
* AVIOPTS.C
*
* routine for bringing up the compression options dialog
*
* AVISaveOptions()
*
* Copyright (c) 1992 - 1995 Microsoft Corporation. All Rights Reserved.
*
* You have a royalty-free right to use, modify, reproduce and
* distribute the Sample Files (and/or any modified version) in
* any way you find useful, provided that you agree that
* Microsoft has no warranty obligations or liability for any
* Sample Application Files which are modified.
*
***************************************************************************/
#include <win32.h>
#include <mmreg.h>
#include <msacm.h>
#include <vfw.h>
#include "aviopts.h"
#include "avifile.rc"
#if !defined NUMELMS
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
#endif
/****************************************************************************
***************************************************************************/
extern HINSTANCE ghMod;
INT_PTR FAR PASCAL _export AVICompressOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
/****************************************************************************
***************************************************************************/
int gnNumStreams = 0; // how many streams in array
int gnCurStream = 0; // which stream's options we're setting
PAVISTREAM FAR *gapAVI; // array of stream pointers
LPAVICOMPRESSOPTIONS FAR *gapOpt; // array of option structures to fill
UINT guiFlags;
COMPVARS gCompVars; // for ICCompressorChoose
/****************************************************************************
***************************************************************************/
/*************************************************************
* @doc EXTERNAL AVISaveOptions
*
* @api BOOL | AVISaveOptions | This function gets the save options for
* a file and returns them in a buffer.
*
* @parm HWND | hwnd | Specifies the parent window handle for the Compression Options
* dialog box.
*
* @parm UINT | uiFlags | Specifies the flags for displaying the
* Compression Options dialog box. The following flags are defined:
*
* @flag ICMF_CHOOSE_KEYFRAME | Displays a "Key frame every" box for
* the video options. This is the same flag used in <f ICCompressorChoose>.
*
* @flag ICMF_CHOOSE_DATARATE | Displays a "Data rate" box for the video
* options. This is the same flag used in <f ICCompressorChoose>.
*
* @flag ICMF_CHOOSE_PREVIEW | Displays a "Preview" button for
* the video options. This button previews the compression
* using a frame from the stream. This is the same flag
* used in <f ICCompressorChoose>.
*
* @parm int | nStreams | Specifies the number of streams
* that will have their options set by the dialog box.
*
* @parm PAVISTREAM FAR * | ppavi | Specifies a pointer to an
* array of stream interface pointers. The <p nStreams>
* parameter indicates the number of pointers in the array.
*
* @parm LPAVICOMPRESSOPTIONS FAR * | plpOptions | Specifies a pointer
* to an array of <t LPAVICOMPRESSOPTIONS> pointers
* to hold the compression options set by the dialog box. The
* <p nStreams> parameter indicates the number of
* pointers in the array.
*
* @rdesc Returns TRUE if the user pressed OK, FALSE for CANCEL or an error.
*
* @comm This function presents a standard Compression Options dialog
* box using <p hwnd> as the parent window handle. When the
* user is finished selecting the compression options for
* each stream, the options are returned in the <t AVICOMPRESSOPTIONS>
* structures in the array referenced by <p lpOptions>. The caller
* must pass the interface pointers for the streams
* in the array referenced by <p ppavi>.
*
******************************************************************/
STDAPI_(INT_PTR) AVISaveOptions(HWND hwnd, UINT uiFlags, int nStreams, PAVISTREAM FAR *ppavi, LPAVICOMPRESSOPTIONS FAR *plpOptions)
{
INT_PTR f;
AVICOMPRESSOPTIONS FAR *aOptions;
int i;
/* Save the stream pointer */
gnNumStreams = nStreams;
gnCurStream = -1;
gapAVI = ppavi;
gapOpt = plpOptions;
guiFlags = uiFlags;
//
// Remember the old compression options in case we cancel and need to
// restore them
//
aOptions = (AVICOMPRESSOPTIONS FAR *)GlobalAllocPtr(GMEM_MOVEABLE,
nStreams * sizeof(AVICOMPRESSOPTIONS));
if (!aOptions)
return FALSE;
#if 0 //def _WIN32
CopyMemory((PVOID)aOptions, (PVOID)*plpOptions, nStreams * sizeof(AVICOMPRESSOPTIONS));
#else
// We really ought to use memcpy on this...
for (i = 0; i < nStreams; i++)
aOptions[i] = *plpOptions[i];
#endif
f = DialogBox (ghMod, MAKEINTRESOURCE(IDD_COMPRESSOPTIONS), hwnd,
AVICompressOptionsDlgProc);
//
// The user cancelled... put the old compression options back.
//
if (f == 0) {
#if 0 //def _WIN32
CopyMemory((PVOID)*plpOptions, (PVOID)aOptions, nStreams * sizeof(AVICOMPRESSOPTIONS));
#else
// We really ought to use memcpy on this...
for (i = 0; i < nStreams; i++)
*plpOptions[i] = aOptions[i];
#endif
}
// Couldn't bring up the dialog
if (f == -1)
f = 0;
GlobalFreePtr(aOptions);
// !!! Returning TRUE doesn't guarantee something actually changed...
return f;
}
/*************************************************************
* @doc EXTERNAL AVISaveOptionsFree
*
* @api LONG | AVISaveOptionsFree | This function frees the resources allocated
* by <f AVISaveOptions>.
*
* @parm int | nStreams | Specifies the number of <t AVICOMPRESSOPTIONS>
* structures in the array passed in as the next parameter.
*
* @parm LPAVICOMPRESSOPTIONS FAR * | plpOptions | Specifies a pointer
* to an array of <t LPAVICOMPRESSOPTIONS> pointers
* to hold the compression options set by the dialog box. The
* resources in each of these structures that were allocated by
* <f AVISaveOptions> will be freed.
*
* @rdesc This function always returns AVIERR_OK (zero)
*
* @comm This function frees the resources allocated by <f AVISaveOptions>.
**************************************************************/
STDAPI AVISaveOptionsFree(int nStreams, LPAVICOMPRESSOPTIONS FAR *plpOptions)
{
for (; nStreams > 0; nStreams--) {
if (plpOptions[nStreams-1]->lpParms)
GlobalFreePtr(plpOptions[nStreams-1]->lpParms);
plpOptions[nStreams-1]->lpParms = NULL;
if (plpOptions[nStreams-1]->lpFormat)
GlobalFreePtr(plpOptions[nStreams-1]->lpFormat);
plpOptions[nStreams-1]->lpFormat = NULL;
}
return AVIERR_OK;
}
/****************************************************************************
Bring up the compression options for the current stream
***************************************************************************/
BOOL StreamOptions(HWND hwnd) {
AVISTREAMINFO avis;
BOOL f = FALSE;
LONG lTemp;
UINT w;
// Get the stream type
if (AVIStreamInfo(gapAVI[gnCurStream], &avis, sizeof(avis)) != 0)
return FALSE;
//
// Video stream -- bring up the video compression dlg
//
if (avis.fccType == streamtypeVIDEO) {
// The structure we have now is not filled in ... init it
if (!(gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_VALID)) {
_fmemset(gapOpt[gnCurStream], 0,
sizeof(AVICOMPRESSOPTIONS));
gapOpt[gnCurStream]->fccHandler = comptypeDIB;
gapOpt[gnCurStream]->dwQuality = (DWORD)ICQUALITY_DEFAULT;
}
_fmemset(&gCompVars, 0, sizeof(gCompVars));
gCompVars.cbSize = sizeof(gCompVars);
gCompVars.dwFlags = ICMF_COMPVARS_VALID;
gCompVars.fccHandler = gapOpt[gnCurStream]->fccHandler;
gCompVars.lQ = gapOpt[gnCurStream]->dwQuality;
gCompVars.lpState = gapOpt[gnCurStream]->lpParms;
gCompVars.cbState = gapOpt[gnCurStream]->cbParms;
gCompVars.lKey =
(gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_KEYFRAMES)?
(gapOpt[gnCurStream]->dwKeyFrameEvery) : 0;
gCompVars.lDataRate =
(gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_DATARATE) ?
(gapOpt[gnCurStream]->dwBytesPerSecond / 1024) : 0;
// !!! Don't pass flags verbatim if others are defined!!!
f = ICCompressorChoose(hwnd, guiFlags, NULL,
gapAVI[gnCurStream], &gCompVars, NULL);
/* Set the options to our new values */
gapOpt[gnCurStream]->lpParms = gCompVars.lpState;
gapOpt[gnCurStream]->cbParms = gCompVars.cbState;
gCompVars.lpState = NULL; // so it won't be freed
gapOpt[gnCurStream]->fccHandler = gCompVars.fccHandler;
gapOpt[gnCurStream]->dwQuality = gCompVars.lQ;
gapOpt[gnCurStream]->dwKeyFrameEvery = gCompVars.lKey;
gapOpt[gnCurStream]->dwBytesPerSecond = gCompVars.lDataRate
* 1024;
if (gCompVars.lKey)
gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_KEYFRAMES;
else
gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_KEYFRAMES;
if (gCompVars.lDataRate)
gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_DATARATE;
else
gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_DATARATE;
// If they pressed OK, we have valid stuff in here now.
if (f)
gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_VALID;
// Close the stuff opened by ICCompressorChoose
ICCompressorFree(&gCompVars);
//
// Bring up the ACM format dialog and stuff it in our
// compression options structure
//
} else if (avis.fccType == streamtypeAUDIO) {
ACMFORMATCHOOSE acf;
LONG lsizeF = 0;
if (acmGetVersion() < 0x02000000L) {
TCHAR achACM[160];
TCHAR achACMV[40];
LoadString(ghMod, IDS_BADACM, achACM, sizeof(achACM)/sizeof(TCHAR));
LoadString(ghMod, IDS_BADACMV, achACMV, sizeof(achACMV)/sizeof(TCHAR));
MessageBox(hwnd, achACM, achACMV, MB_OK | MB_ICONHAND);
return FALSE;
}
_fmemset(&acf, 0, sizeof(acf)); // or ACM blows up
acf.cbStruct = sizeof(ACMFORMATCHOOSE);
// If our options struct has valid data, use it to init
// the acm dialog with, otherwise pick a default.
acf.fdwStyle = (gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_VALID)
? ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT : 0;
acf.hwndOwner = hwnd;
// Make sure the AVICOMPRESSOPTIONS has a big enough lpFormat
acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, (LPVOID)&lTemp);
if ((gapOpt[gnCurStream]->cbFormat == 0 ||
gapOpt[gnCurStream]->lpFormat == NULL) && lTemp) {
gapOpt[gnCurStream]->lpFormat =
GlobalAllocPtr(GMEM_MOVEABLE, lTemp);
gapOpt[gnCurStream]->cbFormat = lTemp;
} else if (gapOpt[gnCurStream]->cbFormat < (DWORD)lTemp && lTemp) {
gapOpt[gnCurStream]->lpFormat =
GlobalReAllocPtr(gapOpt[gnCurStream]->lpFormat, lTemp,
GMEM_MOVEABLE);
gapOpt[gnCurStream]->cbFormat = lTemp;
}
if (!gapOpt[gnCurStream]->lpFormat)
return FALSE;
acf.pwfx = gapOpt[gnCurStream]->lpFormat;
acf.cbwfx = gapOpt[gnCurStream]->cbFormat;
//
// Only ask for choices that we can actually convert to
//
AVIStreamReadFormat(gapAVI[gnCurStream],
AVIStreamStart(gapAVI[gnCurStream]), NULL, &lsizeF);
// !!! Work around ACM bug by making sure our format is big enough
lsizeF = max(lsizeF, sizeof(WAVEFORMATEX));
acf.pwfxEnum = (LPWAVEFORMATEX)
GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, lsizeF);
if (acf.pwfxEnum) {
AVIStreamReadFormat(gapAVI[gnCurStream],
AVIStreamStart(gapAVI[gnCurStream]), acf.pwfxEnum, &lsizeF);
acf.fdwEnum |= ACM_FORMATENUMF_CONVERT;
}
// If they pressed OK, we now have valid stuff in here!
w = acmFormatChoose(&acf);
if (w == MMSYSERR_NOERROR)
gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_VALID;
else if (w != ACMERR_CANCELED) {
MessageBeep(0); // !!! Should really be a message box!
}
if (acf.pwfxEnum)
GlobalFreePtr(acf.pwfxEnum);
f = (w == MMSYSERR_NOERROR);
}
return f;
}
#if defined _WIN32 && !defined UNICODE // Chicago only
/*
* convert a UNICODE string to 'normal'
*/
LPTSTR WINAPI aviWideToText (LPTSTR lpszOut, LPWSTR lpwIn, UINT cch)
{
if (sizeof(TCHAR) != sizeof(WCHAR))
WideCharToMultiByte(CP_ACP, 0, lpwIn, cch, lpszOut, cch, NULL, NULL);
else
lstrcpyn (lpszOut, (LPTSTR)lpwIn, cch);
return lpszOut;
}
#else
#define aviWideToText(lpszOut,lpwIn,cch) lstrcpyn(lpszOut,lpwIn,cch)
#endif // _WIN32 on CHICAGO
STATICDT SZCODE aszXbyXbyX[] = TEXT("%ldx%ldx%d\n");
STATICDT SZCODE aszBlahSpaceBlah[] = TEXT("%s %s");
//
// Somebody chose a new stream. Do we need to grey InterleaveOpts?
// Set the current stream.
//
void NEAR PASCAL NewStreamChosen(HWND hwnd)
{
AVISTREAMINFO avis;
HIC hic;
ICINFO icinfo;
ACMFORMATDETAILS acmfmt;
ACMFORMATTAGDETAILS aftd;
LONG lsizeF;
LPBITMAPINFOHEADER lp = NULL;
TCHAR szFFDesc[80];
TCHAR szDesc[120];
gnCurStream = (int)SendDlgItemMessage(hwnd, IDC_intCHOOSESTREAM,
CB_GETCURSEL, 0, 0L);
if (gnCurStream < 0)
return;
if (AVIStreamInfo(gapAVI[gnCurStream], &avis, sizeof(avis)) != 0)
return;
//
// Show a string describing the current format
//
szDesc[0] = TEXT('\0');
lsizeF = 0;
AVIStreamReadFormat(gapAVI[gnCurStream],
AVIStreamStart(gapAVI[gnCurStream]), NULL, &lsizeF);
if (lsizeF) {
lp = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, lsizeF);
if (lp) {
if (AVIStreamReadFormat(gapAVI[gnCurStream],
AVIStreamStart(gapAVI[gnCurStream]),
lp, &lsizeF) == AVIERR_OK) {
if (avis.fccType == streamtypeVIDEO) {
wsprintf(szDesc, aszXbyXbyX, lp->biWidth,
lp->biHeight, lp->biBitCount);
if (lp->biCompression == BI_RGB) {
LoadString(ghMod, IDS_FFDESC, szFFDesc,
sizeof(szFFDesc)/sizeof(TCHAR));
lstrcat(szDesc, szFFDesc);
} else {
hic = ICDecompressOpen(ICTYPE_VIDEO,avis.fccHandler,
lp, NULL);
if (hic) {
if (ICGetInfo(hic, &icinfo,sizeof(icinfo)) != 0) {
UINT cb = lstrlen(szDesc);
aviWideToText (szDesc + cb,
icinfo.szDescription,
NUMELMS(szDesc) - cb);
}
ICClose(hic);
}
}
} else if (avis.fccType == streamtypeAUDIO) {
_fmemset(&acmfmt, 0, sizeof(acmfmt));
acmfmt.pwfx = (LPWAVEFORMATEX) lp;
acmfmt.cbStruct = sizeof(ACMFORMATDETAILS);
acmfmt.dwFormatTag = acmfmt.pwfx->wFormatTag;
acmfmt.cbwfx = lsizeF;
aftd.cbStruct = sizeof(aftd);
aftd.dwFormatTag = acmfmt.pwfx->wFormatTag;
aftd.fdwSupport = 0;
if ((acmFormatTagDetails(NULL,
&aftd,
ACM_FORMATTAGDETAILSF_FORMATTAG) == 0) &&
(acmFormatDetails(NULL, &acmfmt,
ACM_FORMATDETAILSF_FORMAT) == 0)) {
wsprintf(szDesc, aszBlahSpaceBlah, (LPTSTR) acmfmt.szFormat,
(LPTSTR) aftd.szFormatTag);
}
}
}
GlobalFreePtr(lp);
}
}
SetDlgItemText(hwnd, IDC_intFORMAT, szDesc);
//
// AUDIO and VIDEO streams have a compression dialog
//
if (avis.fccType == streamtypeAUDIO ||
avis.fccType == streamtypeVIDEO)
EnableWindow(GetDlgItem(hwnd, IDC_intOPTIONS), TRUE);
else
EnableWindow(GetDlgItem(hwnd, IDC_intOPTIONS), FALSE);
}
/*--------------------------------------------------------------+
* Dialog Proc for the main compression options dialog *
+--------------------------------------------------------------*/
INT_PTR FAR PASCAL _export AVICompressOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int i, nVal;
AVISTREAMINFO avis;
DWORD dw;
BOOL f;
switch(msg){
case WM_INITDIALOG:
//
// If we've only got one stream to set the options for, it seems
// strange to bring up a box to let you choose which stream you want.
// Let's skip straight to the proper options dlg box.
//
if (gnNumStreams == 1) {
gnCurStream = 0;
EndDialog(hwnd, StreamOptions(hwnd));
return TRUE;
}
/* Add the list of streams to the drop-down box */
for (nVal = 0; nVal < gnNumStreams; nVal++) {
// Get the name of this stream
AVIStreamInfo(gapAVI[nVal], &avis, sizeof(avis));
SendDlgItemMessage(hwnd, IDC_intCHOOSESTREAM, CB_ADDSTRING, 0,
(LONG_PTR) (LPTSTR)avis.szName);
}
// Set our initial selection to the first item
SendDlgItemMessage(hwnd, IDC_intCHOOSESTREAM, CB_SETCURSEL, 0, 0L);
// Make sure we see it
SendMessage(hwnd, WM_COMMAND,
GET_WM_COMMAND_MPS(IDC_intCHOOSESTREAM, hwnd, CBN_SELCHANGE));
// Set the interleave boxes for these streams. Every stream should
// be interleaved the same way, so just look at the first guy.
// !!! Admittedly, some app might only set the interleaving for
// the audio stream, and we won't get his intended default here.
// Default to interleave every 1 if we're uninitialized
if (gapOpt[0]->dwFlags & AVICOMPRESSF_VALID) {
f = (gapOpt[0]->dwFlags & AVICOMPRESSF_INTERLEAVE) != 0;
dw = gapOpt[0]->dwInterleaveEvery;
} else {
dw = 1;
f = FALSE;
}
CheckDlgButton(hwnd, IDC_intINTERLEAVE, f);
SetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT, (int)dw, FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVEEDIT), f);
return TRUE;
case WM_COMMAND:
switch(GET_WM_COMMAND_ID(wParam, lParam)){
case IDOK:
// Set the interleaving for every stream to be the same,
// whatever we have chosen. AVIFile doesn't support
// interleaving different streams in different ways.
f = IsDlgButtonChecked(hwnd, IDC_intINTERLEAVE);
dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT,
NULL, FALSE);
for (i = 0; i < gnNumStreams; i++) {
gapOpt[i]->dwInterleaveEvery = dw;
if (f)
gapOpt[i]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
else
gapOpt[i]->dwFlags &=~AVICOMPRESSF_INTERLEAVE;
}
// fall through (AAAAaaaahhhhh.....)
case IDCANCEL:
EndDialog(hwnd, wParam == IDOK);
break;
case IDC_intOPTIONS:
StreamOptions(hwnd);
break;
//
// Somebody chose a new stream.
//
case IDC_intCHOOSESTREAM:
if (GET_WM_COMMAND_CMD(wParam, lParam) != CBN_SELCHANGE)
break;
NewStreamChosen(hwnd);
break;
case IDC_intINTERLEAVE:
// Enable the "interleave every" edit box iff we've checked it
f = IsDlgButtonChecked(hwnd, IDC_intINTERLEAVE);
EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVEEDIT), f);
break;
default:
break;
}
break;
default:
return FALSE;
}
return FALSE;
}