|
|
/****************************************************************************
* * AVIVIEW.C * * Sample program using the AVIFile read/write routines * * 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 <windows.h>
#include <windowsx.h>
#include <win32.h>
#include <commdlg.h>
#include <vfw.h>
#include <msacm.h>
#include "aviview.h"
#include "aviplay.h"
#include "audplay.h"
#ifdef WIN32
#define muldiv32 MulDiv
#else
extern LONG FAR PASCAL muldiv32(LONG, LONG, LONG); #endif
#define GlobalSizePtr(lp) GlobalSize(GlobalPtrHandle(lp))
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/ typedef LONG (FAR PASCAL *LPWNDPROC)(HWND, UINT, WPARAM, LPARAM); // pointer to a window procedure
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/ static TCHAR gszAppName[]=TEXT("AVIView");
HINSTANCE ghInstApp; HWND ghwndApp; HACCEL ghAccel;
#define SCROLLRANGE 10000
BOOL gfDecompress = TRUE, gfCheat = TRUE; BOOL gfYieldBound, gfReadBound, gfDecompressBound, gfDrawBound;
#define MAXNUMSTREAMS 10
PAVIFILE gpfile; // the current file
PAVISTREAM gapavi[MAXNUMSTREAMS]; // the current streams
AVICOMPRESSOPTIONS gaAVIOptions[MAXNUMSTREAMS];// compression options
LPAVICOMPRESSOPTIONS galpAVIOptions[MAXNUMSTREAMS]; PGETFRAME gapgf[MAXNUMSTREAMS]; // data for decompressing video
HDRAWDIB ghdd[MAXNUMSTREAMS]; // drawdib handles
int gcpavi; // # of streams
PAVISTREAM gpaviAudio; // 1st audio stream found
PAVISTREAM gpaviVideo; // 1st video stream found
#define gfVideoFound (gpaviVideo != NULL)
#define gfAudioFound (gpaviAudio != NULL)
BOOL gfPlaying; // are we currently playing?
LONG glPlayStartTime; // When did we start playing?
LONG glPlayStartPos; // Where were we on the scrollbar?
LONG timeStart; // cached start, end, length
LONG timeEnd; LONG timeLength; LONG timehscroll; // how much arrows scroll HORZ bar
LONG vertSBLen; // vertical scroll bar
LONG vertHeight;
DWORD gdwMicroSecPerPixel = 1000L; // scale for video
TCHAR gachFileName[128] = TEXT(""); TCHAR gachSaveFileName[128] = TEXT(""); WORD gwZoom = 2; // one-half zoom (divide by 4)
// constants for painting
#define VSPACE 8 // some vertical spacing
#define HSPACE 4 // space between frames for video stream
#define TSPACE 20 // space for text area about each stream
#define AUDIOVSPACE 64 // height of an audio stream at X1 zoom
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
// Macros to get and set the scroll bar to a given millisecond value in the
// movie. Movie lengths can be DWORDS but we only have 16 bits of resolution.
#define GetScrollTime(hwnd) \
(timeStart + muldiv32(GetScrollPos(hwnd, SB_HORZ), timeLength, SCROLLRANGE))
#define SetScrollTime(hwnd, time) SetScrollPos(hwnd, SB_HORZ, \
(int)muldiv32((time) - timeStart, SCROLLRANGE, timeLength), TRUE)
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
LONG FAR PASCAL _export AppWndProc (HWND hwnd, unsigned uiMessage, WPARAM wParam, LPARAM lParam); int ErrMsg (LPTSTR sz,...);
LONG NEAR PASCAL AppCommand(HWND hwnd, unsigned msg, WPARAM wParam, LPARAM lParam);
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
int fWait = 0;
//
// Start a wait operation... put up the hourglass if it's the first call
//
void StartWait() { if (fWait++ == 0) { SetCursor(LoadCursor(NULL,IDC_WAIT)); } }
//
// Once every one who started a wait is finished, go back to regular cursor
//
void EndWait() { if (--fWait == 0) { SetCursor(LoadCursor(NULL,IDC_ARROW)); InvalidateRect(ghwndApp, NULL, TRUE); } }
//
// Code to yield while we're not calling GetMessage.
// Dispatch all messages. Pressing ESC or closing aborts.
//
BOOL WinYield() { MSG msg; BOOL fAbort=FALSE;
while(fWait > 0 && 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; TranslateMessage(&msg); DispatchMessage(&msg); } return fAbort; }
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
//
// When we load a file or zoom changes, we re-set the scrollbars
//
void FixScrollbars(HWND hwnd) { AVISTREAMINFO avis; LONG r, lHeight = 0; UINT w; int i; RECT rc;
//
// Walk through all streams and determine how many pixels it will take to
// draw it.
//
for (i = 0; i < gcpavi; i++) {
AVIStreamInfo(gapavi[i], &avis, sizeof(avis));
if (avis.fccType == streamtypeVIDEO) {
//
// Set the horizontal scrollbar scale to show every frame
// of the first video stream exactly once
//
if (gapavi[i] == gpaviVideo) { w = (avis.rcFrame.right - avis.rcFrame.left) * gwZoom / 4 + HSPACE; r = (LONG)(avis.dwRate / avis.dwScale); gdwMicroSecPerPixel = muldiv32(1000000, 1, w * r); timehscroll = 1000 / r; // msec per frame
}
lHeight += TSPACE + (avis.rcFrame.bottom - avis.rcFrame.top) * gwZoom / 4 + TSPACE; } else if (avis.fccType == streamtypeAUDIO) { lHeight += TSPACE + AUDIOVSPACE * gwZoom / 4; }
//
// Every stream has this much space
//
lHeight += TSPACE + VSPACE; }
//
// Set vertical scrollbar for scrolling the visible area
//
GetClientRect(hwnd, &rc); vertHeight = lHeight; // total height in pixels of entire display
//
// We won't fit in the window... need scrollbars
//
if (lHeight > rc.bottom) { vertSBLen = lHeight - rc.bottom; SetScrollRange(hwnd, SB_VERT, 0, (int)vertSBLen, TRUE); SetScrollPos(hwnd, SB_VERT, 0, TRUE);
//
// We will fit in the window! No scrollbars necessary
//
} else { vertSBLen = 0; SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE); } }
//
// Initialize the streams of a loaded file -- the compression options, the
// DrawDIB handles, and the scroll bars
//
void InitStreams(HWND hwnd) { AVISTREAMINFO avis; LONG lTemp; int i;
//
// Start with bogus times
//
timeStart = 0x7FFFFFFF; timeEnd = 0;
//
// Walk through and init all streams loaded
//
for (i = 0; i < gcpavi; i++) {
AVIStreamInfo(gapavi[i], &avis, sizeof(avis));
//
// Save and SaveOptions code takes a pointer to our compression opts
//
galpAVIOptions[i] = &gaAVIOptions[i];
//
// clear options structure to zeroes
//
_fmemset(galpAVIOptions[i], 0, sizeof(AVICOMPRESSOPTIONS));
//
// Initialize the compression options to some default stuff
// !!! Pick something better
//
galpAVIOptions[i]->fccType = avis.fccType;
switch(avis.fccType) {
case streamtypeVIDEO: galpAVIOptions[i]->dwFlags = AVICOMPRESSF_VALID | AVICOMPRESSF_KEYFRAMES | AVICOMPRESSF_DATARATE; galpAVIOptions[i]->fccHandler = mmioFOURCC('M', 'S', 'V', 'C'); galpAVIOptions[i]->dwQuality = (DWORD)ICQUALITY_DEFAULT; galpAVIOptions[i]->dwKeyFrameEvery = 7; // !!! ask compressor?
galpAVIOptions[i]->dwBytesPerSecond = 60000; break;
case streamtypeAUDIO: galpAVIOptions[i]->dwFlags |= AVICOMPRESSF_VALID; galpAVIOptions[i]->dwInterleaveEvery = 5; #ifdef USE_ACM
acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, (LPVOID) &galpAVIOptions[i]->cbFormat); #endif
galpAVIOptions[i]->lpFormat = GlobalAllocPtr(GHND, galpAVIOptions[i]->cbFormat);
lTemp = galpAVIOptions[i]->cbFormat; // Use current format as default format
AVIStreamReadFormat(gapavi[i], 0, galpAVIOptions[i]->lpFormat, &lTemp); break;
default: break; }
//
// We're finding the earliest and latest start and end points for
// our scrollbar.
//
timeStart = min(timeStart, AVIStreamStartTime(gapavi[i])); timeEnd = max(timeEnd, AVIStreamEndTime(gapavi[i]));
//
// Initialize video streams for getting decompressed frames to display
//
if (avis.fccType == streamtypeVIDEO) {
gapgf[i] = AVIStreamGetFrameOpen(gapavi[i], NULL);
if (gapgf[i] == NULL) continue; ghdd[i] = DrawDibOpen(); // !!! DrawDibBegin?
if (gpaviVideo == NULL) {
//
// Remember the first video stream --- treat it specially
//
gpaviVideo = gapavi[i]; }
} else if (avis.fccType == streamtypeAUDIO) {
//
// Remember the first audio stream --- treat it specially
//
if (gpaviAudio == NULL) gpaviAudio = gapavi[i];
}
}
timeLength = timeEnd - timeStart;
SetScrollRange(hwnd, SB_HORZ, 0, SCROLLRANGE, TRUE); SetScrollTime(hwnd, timeStart);
FixScrollbars(hwnd); }
//
// Update the window title to reflect what's loaded
//
void FixWindowTitle(HWND hwnd) { TCHAR ach[80];
wsprintf(ach, TEXT("%s %s"), (LPTSTR)gszAppName, (LPTSTR)gachFileName);
SetWindowText(hwnd, ach);
InvalidateRect(hwnd, NULL, TRUE); }
//
// Free up the resources associated with DrawDIB
//
void FreeDrawStuff(HWND hwnd) { int i;
// Make sure we're not playing!
aviaudioStop();
for (i = 0; i < gcpavi; i++) { if (gapgf[i]) { AVIStreamGetFrameClose(gapgf[i]); gapgf[i] = NULL; } if (ghdd[i]) { DrawDibClose(ghdd[i]); ghdd[i] = 0; } } SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE); gpaviVideo = gpaviAudio = NULL; }
//
// Free the resources associated with an open file
//
void FreeAvi(HWND hwnd) { int i;
FreeDrawStuff(hwnd);
for (i = 0; i < gcpavi; i++) { AVIStreamClose(gapavi[i]); if (galpAVIOptions[i]->lpFormat) { GlobalFreePtr(galpAVIOptions[i]->lpFormat); } } if (gpfile) AVIFileClose(gpfile);
gpfile = NULL; gcpavi = 0; }
//
// Open up our fake "ball" file as an installible stream hander
// !!! Document how someone goes about writing their own !!!
//
void InitBall(HWND hwnd) { PAVISTREAM FAR PASCAL NewBall(void);
// close everything down
FreeAvi(hwnd);
//
// The NewBall() function creates a PAVISTREAM we can use as it it was
// an AVI file.
//
gapavi[0] = NewBall();
if (gapavi[0]) gcpavi = 1;
lstrcpy(gachFileName, TEXT("BALL")); InitStreams(hwnd); FixWindowTitle(hwnd); }
//
// Open up a file through the AVIFile handlers
//
void InitAvi(HWND hwnd, LPTSTR szFile, UINT wMenu) { HRESULT hr; int i; PAVIFILE pfile;
//
// If we're opening something new, close other open files, otherwise
// just close the draw stuff so we'll merge streams with the new file
//
if (wMenu == MENU_OPEN) FreeAvi(hwnd); else FreeDrawStuff(hwnd);
hr = AVIFileOpen(&pfile, szFile, 0, 0L);
if (hr != 0) goto error;
//
// Get all the streams from the new file
//
for (i = gcpavi; i < MAXNUMSTREAMS; i++) { if (AVIFileGetStream(pfile, &gapavi[i], 0L, i - gcpavi) != AVIERR_OK) break; }
//
// Something went wrong before we finished
//
if (gcpavi == i) { error: ErrMsg(TEXT("Unable to open %s"), (LPTSTR)szFile); if (pfile) AVIFileClose(pfile); return; }
gcpavi = i;
// !!! Play code won't see merged streams
if (!gpfile) gpfile = pfile; else AVIFileClose(pfile);
InitStreams(hwnd); FixWindowTitle(hwnd); }
/*----------------------------------------------------------------------------*\
| AppInit( hInst, hPrev) | | | | Description: | | This is called when the application is first loaded into | | memory. It performs all initialization that doesn't need to be done | | once per instance. | | | | Arguments: | | hInstance instance handle of current instance | | hPrev instance handle of previous instance | | | | Returns: | | TRUE if successful, FALSE if not | | | \*----------------------------------------------------------------------------*/ BOOL AppInit(HINSTANCE hInst, HINSTANCE hPrev, UINT sw, LPSTR szCmdLine) { WNDCLASS cls;
//
// Save instance handle for DialogBoxs
//
ghInstApp = hInst;
ghAccel = LoadAccelerators(hInst, MAKEINTATOM(ID_APP));
#ifndef UNICODE // command line is ansi - can't be bothered to convert it
//
// Did we get passed a filename on the command line? We'll open it at create
// time.
//
if (szCmdLine && szCmdLine[0]) lstrcpy(gachFileName, szCmdLine); #endif
if (!hPrev) { /*
* Register a class for the main application window */ cls.hCursor = LoadCursor(NULL,IDC_ARROW); cls.hIcon = LoadIcon(hInst,MAKEINTATOM(ID_APP)); cls.lpszMenuName = MAKEINTATOM(ID_APP); cls.lpszClassName = MAKEINTATOM(ID_APP); cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); cls.hInstance = hInst; cls.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS; cls.lpfnWndProc = (LPWNDPROC)AppWndProc; cls.cbWndExtra = 0; cls.cbClsExtra = 0;
if (!RegisterClass(&cls)) return FALSE; }
//
// Must be called before using any of the AVIFile routines
//
AVIStreamInit();
//
// Create our main application window
//
ghwndApp = CreateWindow ( MAKEINTATOM(ID_APP), // Class name
gszAppName, // Caption
WS_OVERLAPPEDWINDOW, // Style bits
CW_USEDEFAULT, 0, // Position
320,300, // Size
(HWND)NULL, // Parent window (no parent)
(HMENU)NULL, // use class menu
hInst, // handle to window instance
(LPSTR)NULL // no params to pass on
); ShowWindow(ghwndApp,sw);
return TRUE; }
/*----------------------------------------------------------------------------*\
| WinMain( hInst, hPrev, lpszCmdLine, cmdShow ) | | | | Description: | | The main procedure for the App. After initializing, it just goes | | into a message-processing loop until it gets a WM_QUIT message | | (meaning the app was closed). | | | | Arguments: | | hInst instance handle of this instance of the app | | hPrev instance handle of previous instance, NULL if first | | szCmdLine ->null-terminated command line | | cmdShow specifies how the window is initially displayed | | | | Returns: | | The exit code as specified in the WM_QUIT message. | | | \*----------------------------------------------------------------------------*/ int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) { MSG msg;
//
// Call our initialization procedure
//
if (!AppInit(hInst, hPrev, sw, szCmdLine)) return FALSE;
/*
* Polling messages from event queue */ for (;;) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break;
if (TranslateAccelerator(ghwndApp, ghAccel, &msg)) continue; TranslateMessage(&msg); DispatchMessage(&msg); }
//
// If we have no messages to dispatch, we do our background task...
// If we're playing a file, we set the scroll bar to show the video
// frames corresponding with the current playing audio sample
//
else if (gfPlaying) { LONG l;
//
// Use the audio clock to tell how long we've been playing. To
// maintain sync, it's important we use this clock.
//
l = aviaudioTime(); // returns -1 if no audio playing
//
// If we can't use the audio clock to tell us how long we've been
// playing, calculate it ourself
//
if (l == -1) l = timeGetTime() - glPlayStartTime + glPlayStartPos;
if (l != GetScrollTime(ghwndApp)) { if (l < timeStart) // make sure number isn't out of bounds
l = timeStart; if (l > timeEnd) // looks like we're all done!
gfPlaying = FALSE; SetScrollTime(ghwndApp, l); InvalidateRect(ghwndApp, NULL, FALSE); UpdateWindow(ghwndApp);
continue; }
WaitMessage(); } }
return msg.wParam; }
typedef BYTE _huge * HPBYTE; typedef int _huge * HPINT;
//
// Draw a video frame in the specified rect
//
void PaintVideo(HDC hdc, RECT rcFrame, int iStream, LPBITMAPINFOHEADER lpbi, int iCurFrame, LONG lPos) { int iLen; TCHAR ach[200]; RECT rc;
//
// If we have a picture, draw it
//
if (lpbi) { //
// use the palette of the first video stream
//
DrawDibDraw(ghdd[iStream], hdc, rcFrame.left, rcFrame.top, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top, lpbi, NULL, 0, 0, -1, -1, gapavi[iStream] == gpaviVideo ? 0 :DDF_BACKGROUNDPAL);
iLen = wsprintf(ach, TEXT("%d %ld.%03lds"), iCurFrame, lPos / 1000, lPos % 1000); }
//
// Before or after the movie (or read error) draw GRAY
//
else { SelectObject(hdc,GetStockObject(DKGRAY_BRUSH));
PatBlt(hdc, rcFrame.left, rcFrame.top, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top, PATCOPY); iLen = 0; ach[0] = TEXT('\0'); }
//
// print something meaningful under the frame
//
rc.left = rcFrame.left; rc.right = rcFrame.right + HSPACE; rc.top = rcFrame.bottom + VSPACE; rc.bottom = rc.top + TSPACE; ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, ach, iLen, NULL); }
//
// Draw some samples of audio inside the given rectangle
//
void PaintAudio(HDC hdc, PRECT prc, PAVISTREAM pavi, LONG lStart, LONG lLen) { PCMWAVEFORMAT wf; int i; int x,y; int w,h; BYTE b; HBRUSH hbr; RECT rc = *prc; LONG lBytes; LONG l, lLenOrig = lLen; LONG lWaveBeginTime = AVIStreamStartTime(pavi); LONG lWaveEndTime = AVIStreamEndTime(pavi);
static LPVOID lpAudio = NULL;
//
// We can't draw before the beginning of the stream - adjust
//
if (lStart < lWaveBeginTime) { lLen -= lWaveBeginTime - lStart; lStart = lWaveBeginTime; // right justify the legal samples in the rectangle - don't stretch
rc.left = rc.right - (int)muldiv32(rc.right - rc.left, lLen, lLenOrig); }
//
// We can't draw past the end of the stream
//
if (lStart + lLen > lWaveEndTime) { lLenOrig = lLen; lLen = lWaveEndTime - lStart; // left justify the legal samples in the rectangle - don't stretch
rc.right = rc.left + (int)muldiv32(rc.right - rc.left, lLen, lLenOrig); }
// Now start working with samples, not time
l = lStart; lStart = AVIStreamTimeToSample(pavi, lStart); lLen = AVIStreamTimeToSample(pavi, l + lLen) - lStart;
//
// Get the format of the wave data
//
l = sizeof(wf); AVIStreamReadFormat(pavi, lStart, &wf, &l); if (!l) return;
w = rc.right - rc.left; h = rc.bottom - rc.top;
//
// We were starting before the beginning or continuing past the end.
// We're not painting in the whole original rect --- use a dark background
//
if (rc.left > prc->left) { SelectObject(hdc, GetStockObject(DKGRAY_BRUSH)); PatBlt(hdc, prc->left, rc.top, rc.left - prc->left, rc.bottom - rc.top, PATCOPY); } if (rc.right < prc->right) { SelectObject(hdc, GetStockObject(DKGRAY_BRUSH)); PatBlt(hdc, rc.right, rc.top, prc->right - rc.right, rc.bottom - rc.top, PATCOPY); }
#define BACKBRUSH (GetSysColor(COLOR_BTNFACE)) // background
#define MONOBRUSH (GetSysColor(COLOR_BTNSHADOW)) // for mono audio
#define LEFTBRUSH (RGB(0,0,255)) // left channel
#define RIGHTBRUSH (RGB(0,255,0)) // right channel
#define HPOSBRUSH (RGB(255,0,0)) // current position
//
// Paint the background
//
hbr = SelectObject(hdc, CreateSolidBrush(BACKBRUSH)); PatBlt(hdc, rc.left, rc.top, w, h, PATCOPY); DeleteObject(SelectObject(hdc, hbr));
//
// !!! we can only paint PCM data right now. Sorry!
//
if (wf.wf.wFormatTag != WAVE_FORMAT_PCM) return;
//
// How many bytes are we painting? Alloc some space for them
// !!! These bytes never get freed
//
lBytes = lLen * wf.wf.nChannels * wf.wBitsPerSample / 8; if (!lpAudio) lpAudio = GlobalAllocPtr (GHND, lBytes); else if ((LONG)GlobalSizePtr(lpAudio) < lBytes) lpAudio = GlobalReAllocPtr(lpAudio, lBytes, GMEM_MOVEABLE); if (!lpAudio) return;
//
// Read in the wave data
//
AVIStreamRead(pavi, lStart, lLen, lpAudio, lBytes, NULL, &l); if (l != lLen) return;
#define MulDiv(a,b,c) (UINT)((DWORD)(UINT)(a) * (DWORD)(UINT)(b) / (UINT)(c))
//
// !!! Flickers less painting it NOW or LATER?
// First show the current position as a bar
//
hbr = SelectObject(hdc, CreateSolidBrush(HPOSBRUSH)); PatBlt(hdc, prc->right / 2, prc->top, 1, prc->bottom - prc->top, PATCOPY); DeleteObject(SelectObject(hdc, hbr));
//
// Paint monochrome wave data
//
if (wf.wf.nChannels == 1) {
//
// Draw the x-axis
//
hbr = SelectObject(hdc, CreateSolidBrush(MONOBRUSH)); y = rc.top + h/2; PatBlt(hdc, rc.left, y, w, 1, PATCOPY);
//
// 8 bit data is centred around 0x80
//
if (wf.wBitsPerSample == 8) { for (x=0; x<w; x++) {
// which byte of audio data belongs at this pixel?
b = *((HPBYTE)lpAudio + muldiv32(x, lLen, w));
if (b > 0x80) { i = y - MulDiv(b - 0x80, (h / 2), 128); PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY); } else { i = y + MulDiv(0x80 - b, (h / 2), 128); PatBlt(hdc, rc.left + x, y, 1, i - y, PATCOPY); } } }
//
// 16 bit data is centred around 0x00
//
else if (wf.wBitsPerSample == 16) { for (x=0; x<w; x++) {
// which byte of audio data belongs at this pixel?
i = *((HPINT)lpAudio + muldiv32(x,lLen,w));
if (i > 0) { i = y - (int) ((LONG)i * (h/2) / 32768); PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY); } else { i = (int) ((LONG)i * (h/2) / 32768); PatBlt(hdc, rc.left+x, y, 1, -i, PATCOPY); } } } DeleteObject(SelectObject(hdc, hbr)); } // endif mono
//
// Draw stereo waveform data
//
else if (wf.wf.nChannels == 2) {
//
// 8 bit data is centred around 0x80
//
if (wf.wBitsPerSample == 8) {
// Left channel
hbr = SelectObject(hdc, CreateSolidBrush(LEFTBRUSH)); y = rc.top + h/4; PatBlt(hdc, rc.left, y, w, 1, PATCOPY);
for (x=0; x<w; x++) { b = *((HPBYTE)lpAudio + muldiv32(x,lLen,w) * 2);
if (b > 0x80) { i = y - MulDiv(b-0x80,(h/4),128); PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY); } else { i = y + MulDiv(0x80-b,(h/4),128); PatBlt(hdc, rc.left+x, y, 1, i-y, PATCOPY); } } DeleteObject(SelectObject(hdc, hbr));
// Right channel
hbr = SelectObject(hdc, CreateSolidBrush(RIGHTBRUSH)); y = rc.top + h * 3 / 4; PatBlt(hdc, rc.left, y, w, 1, PATCOPY);
for (x=0; x<w; x++) { b = *((HPBYTE)lpAudio + muldiv32(x,lLen,w) * 2 + 1);
if (b > 0x80) { i = y - MulDiv(b-0x80,(h/4),128); PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY); } else { i = y + MulDiv(0x80-b,(h/4),128); PatBlt(hdc, rc.left+x, y, 1, i-y, PATCOPY); } } DeleteObject(SelectObject(hdc, hbr)); }
//
// 16 bit data is centred around 0x00
//
else if (wf.wBitsPerSample == 16) {
// Left channel
hbr = SelectObject(hdc, CreateSolidBrush(LEFTBRUSH)); y = rc.top + h/4; PatBlt(hdc, rc.left, y, w, 1, PATCOPY);
for (x=0; x<w; x++) { i = *((HPINT)lpAudio + muldiv32(x,lLen,w) * 2); if (i > 0) { i = y - (int) ((LONG)i * (h/4) / 32768); PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY); } else { i = (int) ((LONG)i * (h/4) / 32768); PatBlt(hdc, rc.left+x, y, 1, -i, PATCOPY); } } DeleteObject(SelectObject(hdc, hbr));
// Right channel
hbr = SelectObject(hdc, CreateSolidBrush(RIGHTBRUSH)); y = rc.top + h * 3 / 4; PatBlt(hdc, rc.left, y, w, 1, PATCOPY);
for (x=0; x<w; x++) { i = *((HPINT)lpAudio + muldiv32(x,lLen,w) * 2 + 1); if (i > 0) { i = y - (int) ((LONG)i * (h/4) / 32768); PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY); } else { i = (int) ((LONG)i * (h/4) / 32768); PatBlt(hdc, rc.left+x, y, 1, -i, PATCOPY); } } DeleteObject(SelectObject(hdc, hbr)); } } // endif stereo
}
/*----------------------------------------------------------------------------*\
| AppWndProc( hwnd, uiMessage, wParam, lParam ) | | | | Description: | | The window proc for the app's main (tiled) window. This processes all | | of the parent window's messages. | | | | Arguments: | | hwnd window handle for the window | | uiMessage message number | | wParam message-dependent | | lParam message-dependent | | | | Returns: | | 0 if processed, nonzero if ignored | | | \*----------------------------------------------------------------------------*/ LONG FAR PASCAL _export AppWndProc(hwnd, msg, wParam, lParam) HWND hwnd; unsigned msg; WPARAM wParam; LPARAM lParam; { PAINTSTRUCT ps; BOOL f; HDC hdc; TCHAR ach[200]; int iFrameWidth, iLen; int iFrame, iCurFrame; int n; int nFrames; LPBITMAPINFOHEADER lpbi; LONG l; LONG lTime; LONG lSize = 0; LONG lAudioStart; LONG lAudioLen; RECT rcFrame, rcC; int yStreamTop; int i; HBRUSH hbr; RECT rc;
switch (msg) {
//
// If we passed a command line filename, open it
//
case WM_CREATE: if (gachFileName[0]) InitAvi(hwnd, gachFileName, MENU_OPEN); break;
case WM_COMMAND: return AppCommand(hwnd,msg,wParam,lParam);
case WM_INITMENU: f = !gfPlaying; EnableMenuItem((HMENU)wParam, MENU_OPEN, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_BALL, f ? MF_ENABLED : MF_GRAYED);
f = (gfAudioFound || gfVideoFound) && !gfPlaying; EnableMenuItem((HMENU)wParam, MENU_SAVEAS, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_SAVERAW,f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_OPTIONS,f ? MF_ENABLED : MF_GRAYED);
f = gcpavi > 0 && !gfPlaying; EnableMenuItem((HMENU)wParam, MENU_CLOSE, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_MERGE, f ? MF_ENABLED : MF_GRAYED); f = FALSE; EnableMenuItem((HMENU)wParam, MENU_CUT, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_COPY, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_DELETE, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_PASTE, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_MARK, f ? MF_ENABLED : MF_GRAYED); f = gfVideoFound; EnableMenuItem((HMENU)wParam, MENU_PLAY, (f & !gfPlaying && gpfile) ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_STOP, (f & gfPlaying) ? MF_ENABLED : MF_GRAYED);
CheckMenuItem((HMENU)wParam, MENU_ZOOMQUARTER, (gwZoom == 1) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_ZOOMHALF, (gwZoom == 2) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_ZOOM1, (gwZoom == 4) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_ZOOM2, (gwZoom == 8) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_ZOOM4, (gwZoom == 16) ? MF_CHECKED : MF_UNCHECKED); EnableMenuItem((HMENU)wParam, MENU_PLAY_DECOMPRESS, !gfPlaying ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_PLAY_CHEAT, !gfPlaying ? MF_ENABLED : MF_GRAYED); CheckMenuItem((HMENU)wParam, MENU_PLAY_DECOMPRESS, gfDecompress ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_PLAY_CHEAT, gfCheat ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_PLAY_YIELD_BOUND, gfYieldBound ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_PLAY_READ_BOUND, gfReadBound ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_PLAY_DECOMPRESS_BOUND, gfDecompressBound ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem((HMENU)wParam, MENU_PLAY_DRAW_BOUND, gfDrawBound ? MF_CHECKED : MF_UNCHECKED);
break;
//
// During a wait state (eg saving) don't let us choose any menus
//
case WM_NCHITTEST: if (fWait) {
// Let windows tell us where the cursor is
lParam = DefWindowProc(hwnd,msg,wParam,lParam);
// If it's over a menu, pretend it's in the client (force
// hourglass)
if (lParam == HTMENU) lParam = HTCLIENT;
return lParam; } break;
//
// Set vertical scrollbar for scrolling streams
//
case WM_SIZE: GetClientRect(hwnd, &rc);
//
// There is not enough vertical room to show all streams. Scrollbars
// are required.
//
if (vertHeight > rc.bottom) { vertSBLen = vertHeight - rc.bottom; SetScrollRange(hwnd, SB_VERT, 0, (int)vertSBLen, TRUE);
//
// Everything fits vertically. No scrollbar necessary.
//
} else { vertSBLen = 0; SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE); } break;
//
// During a wait state, show an hourglass over our client area
// !!! Is this necessary?
//
case WM_SETCURSOR: if (fWait && LOWORD(lParam) == HTCLIENT) { SetCursor(LoadCursor(NULL, IDC_WAIT)); return TRUE; } break;
//
// We're out of here!
//
case WM_DESTROY: FreeAvi(hwnd); // close all open streams
AVIStreamExit(); // shuts down the AVIFile system
PostQuitMessage(0); break;
//
// Don't let us close ourselves in a wait state (eg saving)
//
case WM_CLOSE: if (fWait) return 0; break;
//
// Block keyboard access to menus if waiting
//
case WM_SYSCOMMAND: switch (wParam & 0xFFF0) { case SC_KEYMENU: if (fWait) return 0; break; } break;
case WM_PALETTECHANGED:
// It came from us. Ignore it
if ((HWND)wParam == hwnd) break;
case WM_QUERYNEWPALETTE:
hdc = GetDC(hwnd);
//
// Realize the palette of the first video stream
// !!! If first stream isn't video, we're DEAD!
//
if (f = DrawDibRealize(ghdd[0], hdc, FALSE)) InvalidateRect(hwnd,NULL,TRUE);
ReleaseDC(hwnd,hdc);
return f;
case WM_ERASEBKGND: break;
case WM_PAINT: hdc = BeginPaint(hwnd,&ps);
GetClientRect(hwnd, &rcC);
//
// Look at scrollbars to find current position
//
lTime = GetScrollTime(hwnd); yStreamTop = -GetScrollPos(hwnd, SB_VERT);
//
// Walk through all streams and draw something
//
for (i=0; i<gcpavi; i++) { AVISTREAMINFO avis; LONG lEnd, lEndTime;
//
// Get some info and print something about this stream
//
AVIStreamInfo(gapavi[i], &avis, sizeof(avis)); iLen = wsprintf(ach, TEXT("#%d[%4.4hs] Start: %ld Length: %ld "), i, (LPSTR) &avis.fccType, // compressor FOURCC
AVIStreamStart(gapavi[i]), AVIStreamLength(gapavi[i])); TextOut(hdc, HSPACE, yStreamTop, ach, iLen);
yStreamTop += TSPACE; //
// Draw a VIDEO stream
//
if (avis.fccType == streamtypeVIDEO) { if (gapgf[i] == NULL) continue; //
// Which frame belongs at this time?
//
lEndTime = AVIStreamEndTime(gapavi[i]); if (lTime <= lEndTime) iFrame = (int)AVIStreamTimeToSample(gapavi[i], lTime); else { lEnd = AVIStreamEnd(gapavi[i]); iFrame = (int)lEnd + (int)AVIStreamTimeToSample( gapavi[i], lTime - lEndTime); }
//
// how wide is each frame to paint?
//
iFrameWidth = (avis.rcFrame.right - avis.rcFrame.left) * gwZoom / 4 + HSPACE;
//
// how many frames can we fit on each half of the screen?
//
nFrames = (rcC.right - iFrameWidth) / (2 * iFrameWidth); if (nFrames < 0) nFrames = 0; // at least draw *something*
//
// Step through all the frames we'll draw
//
for (n = -nFrames; n <= nFrames; n++) {
//
// Each video stream is drawn as a horizontal line of
// frames, very close together.
// The first video stream shows a different frame in
// each square. Thus the scale of time is determined
// by the first video stream.
// Every other video stream shows whatever
// frame belongs at the time corresponding to the mid-
// point of each square.
//
if (gapavi[i] == gpaviVideo) {
//
// by definition, we know what frame we're drawing..
// (iFrame-n), (iFrame-(n-1)), ..., (iFrame), ...,
// (iFrame+(n-1)), (iFrame+n)
//
iCurFrame = iFrame + n;
//
// what time is it at that frame? This number will
// be printed underneath the frame
//
l = AVIStreamSampleToTime(gapavi[i], iCurFrame);
} else { // NOT the first video stream
//
// What time is it at the midpoint of the square
// we'll draw? That's what frame we use.
//
l = lTime + muldiv32(n * iFrameWidth, gdwMicroSecPerPixel, 1000);
//
// What frame belongs to that time?
//
iCurFrame =(int)AVIStreamTimeToSample(gapavi[i], l);
//
// what time is it at that frame? This number will
// be printed underneath the frame
//
l = AVIStreamSampleToTime(gapavi[i], iCurFrame); }
lpbi = AVIStreamGetFrame(gapgf[i], iCurFrame);
//
// Figure out where to draw this frame
//
rcFrame.left = rcC.right / 2 - (avis.rcFrame.right * gwZoom / 4) / 2 + (n * iFrameWidth); rcFrame.top = yStreamTop + TSPACE; rcFrame.right = rcFrame.left + avis.rcFrame.right * gwZoom / 4; rcFrame.bottom = rcFrame.top + avis.rcFrame.bottom * gwZoom / 4;
//
// draw a border around the current frame. Make the
// one around the centre frame a special colour.
//
if (n == 0) hbr = CreateSolidBrush(RGB(255,0,0)); else hbr = CreateSolidBrush(RGB(255,255,255)); InflateRect(&rcFrame, 1, 1); FrameRect(hdc, &rcFrame, hbr); InflateRect(&rcFrame, -1, -1); DeleteObject (hbr); //
// Now draw the video frame in the computed rectangle
//
PaintVideo(hdc, rcFrame, i, lpbi, iCurFrame, l);
}
//
// Print a description of this stream
//
if (lpbi) AVIStreamSampleSize(gapavi[i], iFrame, &lSize); iLen = wsprintf(ach, TEXT("Frame:%d Time:%ld.%03ld sec Size:%ld bytes %s "), iFrame, lTime/1000,lTime%1000,lSize, (LPTSTR)(AVIStreamFindKeyFrame(gapavi[i], iFrame, 0) == iFrame ? TEXT("Key") : TEXT(""))); TextOut(hdc, HSPACE, yStreamTop, ach, iLen);
//
// Move down to where we can draw the next stream
//
yStreamTop += TSPACE + (rcFrame.bottom - rcFrame.top) + TSPACE; }
//
// Draw an AUDIO stream
//
else if (avis.fccType == streamtypeAUDIO) { //
// Figure out which samples are visible
//
lAudioStart = lTime - muldiv32(rcC.right / 2, gdwMicroSecPerPixel, 1000); lAudioLen = 2 * (lTime - lAudioStart);
//
// print something useful about this stream
//
iLen = wsprintf(ach, TEXT("Time:%ld %ld samples shown (well, kinda) "), lTime, AVIStreamTimeToSample(gapavi[i], lAudioLen)); // !!! Fix the SAMPLE field for short audio clips !!!
TextOut(hdc, HSPACE, yStreamTop, ach, iLen);
//
// Make the rectangle to draw audio into
//
rc.left = rcC.left; rc.right = rcC.right; rc.top = yStreamTop + TSPACE; rc.bottom = rc.top + AUDIOVSPACE * gwZoom / 4;
//
// Actually paint the audio
//
PaintAudio(hdc, &rc, gapavi[i], lAudioStart, lAudioLen);
//
// Move down to where we can draw the next stream
//
yStreamTop += TSPACE + AUDIOVSPACE * gwZoom / 4; }
yStreamTop += VSPACE;
//
// Give up once we're painting below the bottom of the window
//
if (yStreamTop >= rcC.bottom) break; }
EndPaint(hwnd,&ps); break;
//
// handle the keyboard interface
//
case WM_KEYDOWN: switch (wParam) { case VK_UP: PostMessage(hwnd, WM_VSCROLL, SB_LINEUP,0L); break; case VK_DOWN: PostMessage(hwnd, WM_VSCROLL, SB_LINEDOWN,0L); break; case VK_PRIOR: PostMessage(hwnd, WM_HSCROLL, SB_PAGEUP,0L); break; case VK_NEXT: PostMessage(hwnd, WM_HSCROLL, SB_PAGEDOWN,0L); break; case VK_HOME: PostMessage(hwnd, WM_HSCROLL, SB_THUMBPOSITION, 0L); break; case VK_END: PostMessage(hwnd, WM_HSCROLL, SB_THUMBPOSITION, 0x7FFF); break; case VK_LEFT: PostMessage(hwnd, WM_HSCROLL, SB_LINEUP, 0L); break; case VK_RIGHT: PostMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, 0L); break; } break;
case WM_HSCROLL: l = GetScrollTime(hwnd);
switch (GET_WM_HSCROLL_CODE(wParam, lParam)) { case SB_LINEDOWN: l += timehscroll; break; case SB_LINEUP: l -= timehscroll; break; case SB_PAGEDOWN: l += timeLength/10; break; case SB_PAGEUP: l -= timeLength/10; break; case SB_THUMBTRACK: case SB_THUMBPOSITION: l = GET_WM_HSCROLL_POS(wParam, lParam); l = timeStart + muldiv32(l, timeLength, SCROLLRANGE); break; }
if (l < timeStart) l = timeStart;
if (l > timeEnd) l = timeEnd;
if (l == GetScrollTime(hwnd)) break; SetScrollTime(hwnd, l); InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); break;
case WM_VSCROLL: l = GetScrollPos(hwnd, SB_VERT); GetClientRect(hwnd, &rc);
switch (GET_WM_VSCROLL_CODE(wParam, lParam)) { case SB_LINEDOWN: l += 10; break; case SB_LINEUP: l -= 10; break; case SB_PAGEDOWN: l += rc.bottom; break; case SB_PAGEUP: l -= rc.bottom; break;
case SB_THUMBTRACK: case SB_THUMBPOSITION: l = GET_WM_VSCROLL_POS(wParam, lParam); break; }
if (l < 0) l = 0;
if (l > vertSBLen) l = vertSBLen;
if (l == GetScrollPos(hwnd, SB_VERT)) break; SetScrollPos(hwnd, SB_VERT, (int)l, TRUE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); break;
//
// Wave driver wants to tell us something. Pass it on.
//
case MM_WOM_OPEN: case MM_WOM_DONE: case MM_WOM_CLOSE: aviaudioMessage(hwnd, msg, wParam, lParam); break; } return DefWindowProc(hwnd,msg,wParam,lParam); }
//
// Our save callback that prints our progress in our window title bar
//
BOOL FAR PASCAL _export SaveCallback(int iProgress) { TCHAR ach[128];
wsprintf(ach, TEXT("%s - Saving %s: %d%%"), (LPTSTR) gszAppName, (LPTSTR) gachSaveFileName, iProgress);
SetWindowText(ghwndApp, ach);
//
// Give ourselves a chance to abort
//
return WinYield(); }
//
// Process all of our WM_COMMAND messages
//
LONG NEAR PASCAL AppCommand (hwnd, msg, wParam, lParam) HWND hwnd; unsigned msg; WPARAM wParam; LPARAM lParam; { OPENFILENAME ofn;
switch(wParam) { //
// We want out of here!
//
case MENU_EXIT: PostMessage(hwnd,WM_CLOSE,0,0L); break;
//
// Set the compression options for each stream - pass an array of
// streams and an array of compression options structures
//
case MENU_OPTIONS: AVISaveOptions(hwnd, ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_PREVIEW | ICMF_CHOOSE_ALLCOMPRESSORS, gcpavi, gapavi, galpAVIOptions); break; //
// Save all the open streams into a file
//
case MENU_SAVEAS: case MENU_SAVERAW:
gachSaveFileName[0] = 0;
//
// prompt user for file to save
//
ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = NULL; // filter
ofn.lpstrFilter = TEXT("AVI Files\0*.avi\0WAVE Files\0*.wav\0All\0*.*\0"); ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = gachSaveFileName; ofn.nMaxFile = sizeof(gachSaveFileName); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; if (wParam == MENU_SAVEAS) ofn.lpstrTitle = TEXT("Save AVI File"); else if (wParam == MENU_SAVERAW) ofn.lpstrTitle = TEXT("Save Raw"); else ofn.lpstrTitle = TEXT("Please give me a title"); ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = TEXT("avi"); ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL;
//
// If we get a filename, save it
//
if (GetSaveFileName(&ofn)) { FARPROC lpfn = MakeProcInstance((FARPROC)SaveCallback, ghInstApp);
if (lpfn) { DWORD fccHandler[MAXNUMSTREAMS]; int i; HRESULT hr; StartWait();
for (i = 0; i < gcpavi; i++) fccHandler[i] = galpAVIOptions[i]->fccHandler;
// !!! This won't take away audio compression !!!
// We want to save raw -- don't use any video compression
if (wParam == MENU_SAVERAW) for (i = 0; i < gcpavi; i++) galpAVIOptions[i]->fccHandler = 0;
hr = AVISaveV(gachSaveFileName, NULL, (AVISAVECALLBACK) lpfn, gcpavi, gapavi, galpAVIOptions); if (hr != AVIERR_OK) ErrMsg(TEXT("Error saving AVI file"));
// Now put the video compressors back that we stole
for (i = 0; i < gcpavi; i++) galpAVIOptions[i]->fccHandler = fccHandler[i]; EndWait(); FreeProcInstance(lpfn); FixWindowTitle(hwnd); } } break;
//
// Close everything
//
case MENU_CLOSE: FreeAvi(hwnd); gachFileName[0] = TEXT('\0'); FixWindowTitle(hwnd); break; //
// Open a new file, or merge streams with a new file
//
case MENU_OPEN: case MENU_MERGE: gachFileName[0] = 0;
//
// prompt user for file to open
//
ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = NULL; if (wParam == MENU_MERGE) ofn.lpstrTitle = TEXT("Merge With"); else ofn.lpstrTitle = TEXT("Open AVI"); // !!! This is a dumb filter
ofn.lpstrFilter = TEXT("AVI Files\0*.avi\0") TEXT("Wave Files\0*.wav\0") TEXT("FLI/FLC Files\0*.fli;*.flc\0") TEXT("DIB Sequences\0*.dib;*.bmp\0") TEXT("All\0*.*\0"); ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = gachFileName; ofn.nMaxFile = sizeof(gachFileName); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |OFN_HIDEREADONLY; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = NULL; ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL;
//
// If we've got a filename, go open it
//
#ifdef WIN32
if (GetOpenFileName(&ofn)) #else
if (GetOpenFileNamePreview(&ofn)) #endif
InitAvi(hwnd, gachFileName, wParam);
break;
//
// Open the "fake" ball file as our current file
//
case MENU_BALL: InitBall(hwnd); break; case MENU_ZOOMQUARTER: gwZoom = 1; FixScrollbars(hwnd); InvalidateRect(hwnd, NULL, TRUE); break; case MENU_ZOOMHALF: gwZoom = 2; FixScrollbars(hwnd); InvalidateRect(hwnd, NULL, TRUE); break; case MENU_ZOOM1: gwZoom = 4; FixScrollbars(hwnd); InvalidateRect(hwnd, NULL, TRUE); break; case MENU_ZOOM2: gwZoom = 8; FixScrollbars(hwnd); InvalidateRect(hwnd, NULL, TRUE); break; case MENU_ZOOM4: gwZoom = 16; FixScrollbars(hwnd); InvalidateRect(hwnd, NULL, TRUE); break;
case MENU_PLAY_DECOMPRESS: gfDecompress = !gfDecompress; break;
case MENU_PLAY_CHEAT: gfCheat = !gfCheat; break;
case MENU_PLAY_YIELD_BOUND: gfYieldBound = !gfYieldBound; break;
case MENU_PLAY_READ_BOUND: gfReadBound = !gfReadBound; break;
case MENU_PLAY_DECOMPRESS_BOUND: gfDecompressBound = !gfDecompressBound; break;
case MENU_PLAY_DRAW_BOUND: gfDrawBound = !gfDrawBound; break;
case MENU_PLAY: if (gfPlaying || !gpfile) break;
gfPlaying = 1; // Plays the file and sets the scrollbar to where play stopped
SetScrollTime(hwnd, aviPlay(hwnd, gpfile, GetScrollTime(hwnd))); // If we stopped cuz we are closing, then close now
if (gfPlaying == -1) PostMessage(hwnd, WM_CLOSE, 0, 0); gfPlaying = 0; break;
case MENU_STOP: if (gfPlaying) aviStop(); break; } return 0L; }
/*----------------------------------------------------------------------------*\
| ErrMsg - Opens a Message box with a error message in it. The user can | | select the OK button to continue | \*----------------------------------------------------------------------------*/ int ErrMsg (LPTSTR sz,...) { static TCHAR ach[2000]; va_list va;
va_start(va, sz); wvsprintf (ach,sz, va); /* Format the string */ va_end(va); MessageBox(NULL,ach,NULL, MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL); 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] * ICSAMPLE=1 * ****************************************************************************/
#ifdef DEBUG
#define MODNAME "AVIView"
static void FAR cdecl dprintf(LPSTR szFormat, ...) { char ach[128]; va_list va; static BOOL fDebug = -1;
if (fDebug == -1) fDebug = GetProfileIntA("Debug", MODNAME, FALSE);
if (!fDebug) return;
lstrcpyA(ach, MODNAME ": "); va_start(va, szFormat); wvsprintfA(ach+lstrlenA(ach),szFormat, va); va_end(va); lstrcatA(ach, "\r\n");
OutputDebugStringA(ach); }
#endif
|