/**************************************************************************** * * AVIOPTS.C * * routine for bringing up the compression options dialog * * AVISaveOptions() * * Copyright (c) 1992 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 #include #include #include #include "avifile.h" #include "aviopts.h" #include "aviopts.dlg" #ifdef WIN32 //!!! ACK the ACM does not work on NT #define acmGetVersion() 0 #define acmFormatChoose(x) 1 // some error. #define ICCompressorChoose(hwnd,a,b,c,d,e) 0 #define ICCompressorFree(x) #endif /**************************************************************************** ***************************************************************************/ extern HINSTANCE ghMod; LONG FAR PASCAL _export AVICompressOptionsDlgProc(HWND hwnd, unsigned msg, WORD wParam, LONG 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 . * * @flag ICMF_CHOOSE_DATARATE | Displays a "Data rate" box for the video * options. This is the same flag used in . * * @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 . * * @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

* parameter indicates the number of pointers in the array. * * @parm LPAVICOMPRESSOPTIONS FAR * | plpOptions | Specifies a pointer * to an array of pointers * to hold the compression options set by the dialog box. The *

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

as the parent window handle. When the * user is finished selecting the compression options for * each stream, the options are returned in the * structures in the array referenced by

. The caller * must pass the interface pointers for the streams * in the array referenced by

. * ******************************************************************/ STDAPI_(BOOL) AVISaveOptions(HWND hwnd, UINT uiFlags, int nStreams, PAVISTREAM FAR *ppavi, LPAVICOMPRESSOPTIONS FAR *plpOptions) { BOOL 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; for (i = 0; i < nStreams; i++) aOptions[i] = *plpOptions[i]; f = DialogBox (ghMod, "AVICompressOptionsDialog", hwnd, (DLGPROC)AVICompressOptionsDlgProc); // // The user cancelled... put the old compression options back. // if (f == 0) for (i = 0; i < nStreams; i++) *plpOptions[i] = aOptions[i]; // 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 . * * @parm int | nStreams | Specifies the number of * structures in the array passed in as the next parameter. * * @parm LPAVICOMPRESSOPTIONS FAR * | plpOptions | Specifies a pointer * to an array of pointers * to hold the compression options set by the dialog box. The * resources in each of these structures that were allocated by * will be freed. * * @rdesc This function always returns AVIERR_OK (zero) * * @comm This function frees the resources allocated by . **************************************************************/ 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 = DEFAULT_QUALITY; } _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) { char achACM[160]; char achACMV[40]; LoadString(ghMod, IDS_BADACM, achACM, sizeof(achACM)); LoadString(ghMod, IDS_BADACMV, achACMV, sizeof(achACMV)); 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; } void NEAR PASCAL NewStreamChosen(HWND hwnd) { BOOL f; AVISTREAMINFO avis; DWORD dw; HIC hic; ICINFO icinfo; ACMFORMATDETAILS acmfmt; ACMFORMATTAGDETAILS aftd; LONG lsizeF; LPBITMAPINFOHEADER lp = NULL; char szFFDesc[80]; char szDesc[120]; // Set the interleave options for the selection we're leaving // !!! This code also appears in the OK button if (gnCurStream >= 0) { // there is a previous sel if (IsDlgButtonChecked(hwnd, IDC_intINTERLEAVE)) { dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT, NULL, FALSE); gapOpt[gnCurStream]->dwInterleaveEvery = dw; gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_INTERLEAVE; } else { dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT, NULL, FALSE); gapOpt[gnCurStream]->dwInterleaveEvery = dw; gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_INTERLEAVE; } } 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] = '\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, "%ldx%ldx%d\n", lp->biWidth, lp->biHeight, lp->biBitCount); if (lp->biCompression == BI_RGB) { LoadString(ghMod, IDS_FFDESC, szFFDesc, sizeof(szFFDesc)); lstrcat(szDesc, szFFDesc); } else { hic = ICDecompressOpen(ICTYPE_VIDEO,avis.fccHandler, lp, NULL); if (hic) { if (ICGetInfo(hic, &icinfo,sizeof(icinfo)) != 0) lstrcat(szDesc, icinfo.szDescription); 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, "%s %s", (LPSTR) acmfmt.szFormat, (LPSTR) 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); // // Every stream but the first has an interleave options // if (gnCurStream > 0) { EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVE), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVEEDIT), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVETEXT), TRUE); // Set the interleave situation for this stream f = (gapOpt[gnCurStream]->dwFlags & AVICOMPRESSF_INTERLEAVE) != 0; dw = gapOpt[gnCurStream]->dwInterleaveEvery; CheckDlgButton(hwnd, IDC_intINTERLEAVE, f); SetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT, (int)dw, FALSE); } else { EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVE),FALSE); EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVEEDIT), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_intINTERLEAVETEXT), FALSE); } } /*--------------------------------------------------------------+ * Dialog Proc for the main compression options dialog * +--------------------------------------------------------------*/ LONG FAR PASCAL _export AVICompressOptionsDlgProc(HWND hwnd, unsigned msg, WORD wParam, LONG lParam) { int nVal; AVISTREAMINFO avis; DWORD dw; 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) (LPSTR)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, IDC_intCHOOSESTREAM, MAKELONG(GetDlgItem(hwnd, IDC_intCHOOSESTREAM), CBN_SELCHANGE)); return TRUE; case WM_COMMAND: switch(wParam){ case IDOK: // Set the interleave options for the selection we're on // !!! This code also appears in the SELCHANGE code if (gnCurStream >= 0) { // there is a valid selection if (IsDlgButtonChecked(hwnd, IDC_intINTERLEAVE)) { dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT, NULL, FALSE); gapOpt[gnCurStream]->dwInterleaveEvery = dw; gapOpt[gnCurStream]->dwFlags |= AVICOMPRESSF_INTERLEAVE; } else { // why not remember edit box entry anyway? dw = (DWORD)GetDlgItemInt(hwnd, IDC_intINTERLEAVEEDIT, NULL, FALSE); gapOpt[gnCurStream]->dwInterleaveEvery = dw; gapOpt[gnCurStream]->dwFlags &=~AVICOMPRESSF_INTERLEAVE; } } // fall through (AAAAaaaahhhhh.....) case IDCANCEL: EndDialog(hwnd, wParam == IDOK); break; case IDC_intOPTIONS: StreamOptions(hwnd); break; // // Somebody chose a new stream. Do we need to grey InterleaveOpts? // Set the current stream. // case IDC_intCHOOSESTREAM: if (HIWORD(lParam) != CBN_SELCHANGE) break; NewStreamChosen(hwnd); break; case IDC_intINTERLEAVE: break; default: break; } break; default: return FALSE; } return FALSE; }