#include #include #include #include #include #define CLIPSTUFF #ifdef CLIPSTUFF #include #endif #include #define TEST_FINDSAMPLE #ifndef streamtypeTEXT #pragma message("streamtypeTEXT is not defined in AVIFMT.H") #define streamtypeTEXT mmioFOURCC('t', 'x', 't', 's') #endif #include #include "aviview.h" #include "audplay.h" #define GlobalSizePtr(lp) GlobalSize(GlobalPtrHandle(lp)) #ifndef WIN32 extern LONG FAR PASCAL muldiv32(LONG, LONG, LONG); #endif extern BOOL RegisterObjects(void); extern void RevokeObjects(void); TCHAR gachFilter[512] = TEXT(""); #define FIXCC(fcc) if (fcc == 0) fcc = mmioFOURCC('N', 'o', 'n', 'e'); \ if (fcc == BI_RLE8) fcc = mmioFOURCC('R', 'l', 'e', '8'); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ typedef LONG (FAR PASCAL *LPWNDPROC)(HWND, UINT, WPARAM, LPARAM); // pointer to a window procedure /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ static TCHAR gszAppName[]=TEXT("AVIView"); static HANDLE ghInstApp; static HWND ghwndApp; static HACCEL ghAccel; #define SCROLLRANGE 10000 #define MAXNUMSTREAMS 50 int giCurrentStream; // current stream; PAVIFILE gpfile; // the current file int gaiStreamTop[MAXNUMSTREAMS]; PAVISTREAM gapavi[MAXNUMSTREAMS]; // the current streams PGETFRAME gapgf[MAXNUMSTREAMS]; // data for decompressing // video HDRAWDIB ghdd[MAXNUMSTREAMS]; // drawdib handles HIC ghic[MAXNUMSTREAMS]; // experimental: installable // draw handlers for non-video // streams int gcpavi; // # of streams BOOL gfPlaying = FALSE; // Are we playing right now? LONG glPlayStartTime; // When did we start playing? LONG glPlayStartPos; // From what position? PAVISTREAM gpaviAudio; // 1st audio stream found PAVISTREAM gpaviVideo; // 1st video stream found #define gfVideoFound (gpaviVideo != NULL) #define gfAudioFound (gpaviAudio != NULL) LONG timeStart; // cached start, end, length LONG timeEnd; LONG timeLength; LONG timehscroll; // how much arrows scroll HORZ bar LONG vertSBLen; LONG vertHeight; DWORD gdwMicroSecPerPixel = 1000L; // !!! x-stretch TCHAR gachFileName[MAX_PATH] = TEXT(""); TCHAR gachSaveFileName[MAX_PATH] = TEXT(""); UINT gwZoom = 2; AVICOMPRESSOPTIONS gaAVIOptions[MAXNUMSTREAMS]; LPAVICOMPRESSOPTIONS galpAVIOptions[MAXNUMSTREAMS]; HFONT hfontApp; TEXTMETRIC tm; // !!! constants for painting #define VSPACE 8 // no one will ever know what this means :-( #define HSPACE 4 // space between frames #define TSPACE (tm.tmHeight) // space for text area about each stream #define AUDIOVSPACE 64 // height of an audio stream #define FRAME_BORDER 2 void SaveSmall(PAVISTREAM ps, LPTSTR lpFilename); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ #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,...); BOOL fDialog(int id,HWND hwnd,FARPROC fpfn); LONG NEAR PASCAL AppCommand(HWND hwnd, unsigned msg, WPARAM wParam, LPARAM lParam); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ HCURSOR hcurSave; int fWait = 0; void StartWait() { if (fWait++ == 0) { SetCursor(LoadCursor(NULL,IDC_WAIT)); } } void EndWait() { if (--fWait == 0) { SetCursor(LoadCursor(NULL,IDC_ARROW)); InvalidateRect(ghwndApp, NULL, TRUE); } } 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 + TSPACE / 2 + TSPACE + (avis.rcFrame.bottom - avis.rcFrame.top) * gwZoom / 4; } else if (avis.fccType == streamtypeAUDIO) { lHeight += TSPACE + AUDIOVSPACE * gwZoom / 4; } else if (avis.fccType == streamtypeTEXT) { lHeight += TSPACE + TSPACE; ghic[i] = ICDrawOpen(avis.fccType, avis.fccHandler, NULL); } // // Every stream has this much space // lHeight += TSPACE + TSPACE + 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 = 0; 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; acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, (LPVOID) &galpAVIOptions[i]->cbFormat); 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) { #if 1 gapgf[i] = AVIStreamGetFrameOpen(gapavi[i], NULL); #else // Alternate code for testing AVIStreamGetFrameOpen BITMAPINFOHEADER bih; bih.biSize = sizeof(bih); bih.biClrUsed = 256; bih.biBitCount = 8; bih.biPlanes = 1; bih.biWidth = 0; bih.biHeight = 0; bih.biCompression = BI_RGB; bih.biSizeImage = 0; bih.biClrImportant = 0; gapgf[i] = AVIStreamGetFrameOpen(gapavi[i], &bih); #endif 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); } void FreeDrawStuff(HWND hwnd) { int i; 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; } if (ghic[i]) { ICClose(ghic[i]); ghic[i] = 0; } } SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE); gpaviVideo = gpaviAudio = NULL; } 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; giCurrentStream = 0; } void InitBall(HWND hwnd) { PAVISTREAM FAR PASCAL NewBall(void); FreeAvi(hwnd); gapavi[0] = NewBall(); if (gapavi[0]) gcpavi = 1; lstrcpy(gachFileName, TEXT("BALL")); InitStreams(hwnd); FixWindowTitle(hwnd); } void InsertAVIFile(PAVIFILE pfile, HWND hwnd, LPTSTR lpszFile) { int i; for (i = gcpavi; i < MAXNUMSTREAMS; i++) { gapavi[i] = NULL; if (AVIFileGetStream(pfile, &gapavi[i], 0L, i - gcpavi) != AVIERR_OK) break; if (gapavi[i] == NULL) break; } if (gcpavi == i) { ErrMsg(TEXT("Unable to open %s"), lpszFile); if (pfile) AVIFileClose(pfile); goto exit; } gcpavi = i; if (gpfile) { AVIFileClose(pfile); } else gpfile = pfile; exit: InitStreams(hwnd); FixWindowTitle(hwnd); } void InitAvi(HWND hwnd, LPTSTR szFile, UINT wMenu) { HRESULT hr; PAVIFILE pfile; hr = AVIFileOpen(&pfile, szFile, OF_SHARE_DENY_WRITE, 0L); if (hr != 0) { ErrMsg(TEXT("Unable to open %s"), szFile); return; } if (wMenu == MENU_OPEN) FreeAvi(hwnd); else FreeDrawStuff(hwnd); InsertAVIFile(pfile, hwnd, szFile); } /*----------------------------------------------------------------------------*\ | 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, int sw,LPSTR szCmdLine) { WNDCLASS cls; int dx,dy; /* Save instance handle for DialogBoxs */ ghInstApp = hInst; ghAccel = LoadAccelerators(hInst, MAKEINTATOM(ID_APP)); if (szCmdLine && szCmdLine[0]) { #ifdef UNICODE // convert to unicode lstrcpy(gachFileName, GetCommandLine()); #else 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; } AVIStreamInit(); RegisterObjects(); {HDC hdc; hfontApp = GetStockObject(ANSI_VAR_FONT); hdc = GetDC(NULL); SelectObject(hdc, hfontApp); GetTextMetrics(hdc, &tm); ReleaseDC(NULL, hdc); } dx = GetSystemMetrics (SM_CXSCREEN); dy = GetSystemMetrics (SM_CYSCREEN); ghwndApp = CreateWindowEx( #ifdef BIDI WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON, #else 0, #endif 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 (HANDLE)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 initialization procedure */ if (!AppInit(hInst,hPrev,sw,szCmdLine)) return FALSE; /* * Polling messages from event queue */ for (;;) { while (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)) { if (msg.message == WM_QUIT) return msg.wParam; 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 // 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; 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've been told to draw some times that don't exist if (lStart < lWaveBeginTime) { lLen -= lWaveBeginTime - lStart; lStart = lWaveBeginTime; rc.left = rc.right - (int)muldiv32(rc.right - rc.left, lLen, lLenOrig); } if (lStart + lLen > lWaveEndTime) { lLenOrig = lLen; lLen = lWaveEndTime - lStart; rc.right = rc.left + (int)muldiv32(rc.right - rc.left, lLen, lLenOrig); } /* Now change and work with samples, not time. */ l = lStart; lStart = AVIStreamTimeToSample(pavi, lStart); lLen = AVIStreamTimeToSample(pavi, l + lLen) - lStart; l = sizeof(wf); AVIStreamReadFormat(pavi, lStart, &wf, &l); if (!l) return; w = rc.right - rc.left; h = rc.bottom - rc.top; 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); } #ifdef WIN32 #define BACKBRUSH (RGB(0, 0, 0)) #define MONOBRUSH (RGB(0,255,0)) #define LEFTBRUSH (RGB(0,0,255)) #define RIGHTBRUSH (RGB(0,255,0)) #define HPOSBRUSH (RGB(255,0,0)) #else #define BACKBRUSH (GetSysColor(COLOR_3DFACE)) #define MONOBRUSH (GetSysColor(COLOR_3DSHADOW)) #define LEFTBRUSH (RGB(0,0,255)) #define RIGHTBRUSH (RGB(0,255,0)) #define HPOSBRUSH (RGB(255,0,0)) #endif hbr = SelectObject(hdc, CreateSolidBrush(BACKBRUSH)); PatBlt(hdc, rc.left, rc.top, w, h, PATCOPY); DeleteObject(SelectObject(hdc, hbr)); // // !!! we can only paint PCM data // if (wf.wf.wFormatTag != WAVE_FORMAT_PCM) return; 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; AVIStreamRead(pavi, lStart, lLen, lpAudio, lBytes, NULL, &l); if (l != lLen) ; // FatalAppExit(0, "BLAH!!!"); lLen = l; if (lLen == 0) 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)); // Mono if (wf.wf.nChannels == 1) { hbr = SelectObject(hdc, CreateSolidBrush(MONOBRUSH)); y = rc.top + h/2; PatBlt(hdc, rc.left, y, w, 1, PATCOPY); if (wf.wBitsPerSample == 8) { for (x=0; x 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); } } } else if (wf.wBitsPerSample == 16) { for (x=0; x 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 // Stereo else if (wf.wf.nChannels == 2) { 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 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); } } // Right channel DeleteObject(SelectObject(hdc, hbr)); hbr = SelectObject(hdc, CreateSolidBrush(RIGHTBRUSH)); y = rc.top + h * 3 / 4; PatBlt(hdc, rc.left, y, w, 1, PATCOPY); for (x=0; x 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)); } 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 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); } } // Right channel DeleteObject(SelectObject(hdc, hbr)); hbr = SelectObject(hdc, CreateSolidBrush(RIGHTBRUSH)); y = rc.top + h * 3 / 4; PatBlt(hdc, rc.left, y, w, 1, PATCOPY); for (x=0; x 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; int iLen; LONG lFrame, lCurFrame; int n; int nFrames; LPBITMAPINFOHEADER lpbi; static BYTE abFormat[1024]; LONG l; LONG lTime; LONG lSize = 0; LONG lAudioStart; LONG lAudioLen; RECT rcFrame, rcC; int yStreamTop; int i; HBRUSH hbr; RECT rc; HRESULT hr; switch (msg) { 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 = gcpavi > 0; EnableMenuItem((HMENU)wParam, MENU_SAVE, MF_GRAYED); 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; EnableMenuItem((HMENU)wParam, MENU_NEW, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_ADD, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_COPY, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_PLAY_STREAM,f ? MF_ENABLED : MF_GRAYED); f = gpfile != 0; EnableMenuItem((HMENU)wParam, MENU_CFILE, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_PLAY_FILE, f ? MF_ENABLED : MF_GRAYED); f = TRUE; EnableMenuItem((HMENU)wParam, MENU_PASTE, f ? MF_ENABLED : MF_GRAYED); f = FALSE; EnableMenuItem((HMENU)wParam, MENU_CUT, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_DELETE, f ? MF_ENABLED : MF_GRAYED); EnableMenuItem((HMENU)wParam, MENU_MARK, f ? MF_ENABLED : MF_GRAYED); f = gfAudioFound; EnableMenuItem((HMENU)wParam, MENU_SAVEWAVE,f ? MF_ENABLED : MF_GRAYED); f = gfVideoFound || gfAudioFound; EnableMenuItem((HMENU)wParam, MENU_PLAY, (f && !gfPlaying) ? 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); break; case WM_NCHITTEST: if (fWait) { lParam = DefWindowProc(hwnd,msg,wParam,lParam); if (lParam == HTMENU) lParam = HTCLIENT; return lParam; } break; case WM_SIZE: // Set vertical scrollbar for scrolling streams GetClientRect(hwnd, &rc); if (vertHeight > rc.bottom) { vertSBLen = vertHeight - rc.bottom; SetScrollRange(hwnd, SB_VERT, 0, (int)vertSBLen, TRUE); } else { vertSBLen = 0; SetScrollRange(hwnd, SB_VERT, 0, 0, TRUE); } break; case WM_SETCURSOR: if (fWait && LOWORD(lParam) == HTCLIENT) { SetCursor(LoadCursor(NULL, IDC_WAIT)); return TRUE; } break; case WM_DESTROY: FreeAvi(hwnd); RevokeObjects(); AVIStreamExit(); PostQuitMessage(0); break; case WM_CLOSE: if (fWait) return 0; break; case WM_SYSCOMMAND: switch (wParam & 0xFFF0) { case SC_KEYMENU: if (fWait) // block keyboard access to menus if waiting return 0; break; } break; case WM_PALETTECHANGED: if ((HWND)wParam == hwnd) break; case WM_QUERYNEWPALETTE: hdc = GetDC(hwnd); if (f = DrawDibRealize(ghdd[0], hdc, FALSE)) // !!! stream # InvalidateRect(hwnd,NULL,TRUE); ReleaseDC(hwnd,hdc); return f; case WM_ERASEBKGND: break; case WM_PAINT: hdc = BeginPaint(hwnd,&ps); SelectObject(hdc, hfontApp); #define PRINT(sz) \ (TextOut(hdc, TSPACE, yStreamTop, sz, lstrlen(sz)), \ yStreamTop += tm.tmHeight+1) #define PF1(sz,a) (wsprintf(ach, sz, a), PRINT(ach)) #define PF2(sz,a,b) (wsprintf(ach, sz, a, b), PRINT(ach)) #define PF3(sz,a,b,c) (wsprintf(ach, sz, a, b, c), PRINT(ach)) #define PF4(sz,a,b,c,d) (wsprintf(ach, sz, a, b, c, d), PRINT(ach)) #define PF5(sz,a,b,c,d,e) (wsprintf(ach, sz, a, b, c, d, e), PRINT(ach)) #define PF6(sz,a,b,c,d,e,f) (wsprintf(ach, sz, a, b, c, d, e, f), PRINT(ach)) #define PF7(sz,a,b,c,d,e,f,g) (wsprintf(ach, sz, a, b, c, d, e, f, g), PRINT(ach)) #define PF8(sz,a,b,c,d,e,f,g,h) (wsprintf(ach, sz, a, b, c, d, e, f, g, h), PRINT(ach)) #define PF9(sz,a,b,c,d,e,f,g,h,i) (wsprintf(ach, sz, a, b, c, d, e, f, g, h, i), PRINT(ach)) GetClientRect(hwnd, &rcC); lTime = GetScrollTime(hwnd); yStreamTop = -GetScrollPos(hwnd, SB_VERT); for (i=0; ibiCompression); // // display video format // // Video: 160x120x8 (cram) // #ifdef WIN32 PF4(TEXT("Format: %dx%dx%d (%4.4hs)"), (int)lpbi->biWidth, (int)lpbi->biHeight, (int)lpbi->biBitCount, (LPSTR)&lpbi->biCompression); #else PF4(TEXT("Format: %dx%dx%d (%4.4s)"), (int)lpbi->biWidth, (int)lpbi->biHeight, (int)lpbi->biBitCount, (LPSTR)&lpbi->biCompression); #endif // // Which frame belongs at this time? // lEndTime = AVIStreamEndTime(gapavi[i]); if (lTime <= lEndTime) lFrame = AVIStreamTimeToSample(gapavi[i], lTime); else { // we've scrolled past the end of this stream lEnd = AVIStreamEnd(gapavi[i]); lFrame = lEnd + AVIStreamTimeToSample( gapavi[i], lTime - lEndTime); } yStreamTop += TSPACE/2; // 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++) { // !!! If this code didn't have awful rounding errors, // I wouldn't need to special case the first stream. if (gapavi[i] == gpaviVideo) { // by definition, we know what frame we're drawing. lCurFrame = lFrame + n; // what time is it at that frame? l = AVIStreamSampleToTime(gapavi[i], lCurFrame); } else { // What time is it at this pixel? l = lTime + muldiv32(n * iFrameWidth, gdwMicroSecPerPixel, 1000); // Get the frame lCurFrame = AVIStreamTimeToSample(gapavi[i], l); } // !!! // Could actually return an LPBI for invalid frames // so we better force it to NULL. // if (gapgf[i] && lCurFrame >= AVIStreamStart(gapavi[i])) lpbi = AVIStreamGetFrame(gapgf[i], lCurFrame); else lpbi = NULL; // Location of the current frame rcFrame.left = rcC.right / 2 - ((avis.rcFrame.right - avis.rcFrame.left) * gwZoom/4)/2+ (n * iFrameWidth); rcFrame.top = yStreamTop; rcFrame.right = rcFrame.left + (avis.rcFrame.right - avis.rcFrame.left)*gwZoom/4; rcFrame.bottom = rcFrame.top + (avis.rcFrame.bottom - avis.rcFrame.top)*gwZoom/4; // // draw frame around current frame. // 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); if (lpbi) { DrawDibDraw(ghdd[i],hdc, rcFrame.left, rcFrame.top, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top, lpbi, NULL, 0, 0, -1, -1, ((gapavi[i] == gpaviVideo) && fFirstFrame) ? 0 : DDF_BACKGROUNDPAL); fFirstFrame = FALSE; iLen = wsprintf(ach, TEXT("%ld %ld.%03lds"), lCurFrame, l/1000, l%1000); } else { if (gapgf[i]) SelectObject(hdc,GetStockObject(DKGRAY_BRUSH)); else SelectObject(hdc,GetStockObject(LTGRAY_BRUSH)); PatBlt(hdc, rcFrame.left, rcFrame.top, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top, PATCOPY); iLen = 0; ach[0] = TEXT('\0'); } rc.left = rcFrame.left; rc.right = rcFrame.right + HSPACE; rc.top = rcFrame.bottom + 2; rc.bottom = rc.top + TSPACE; ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, ach, iLen, NULL); } yStreamTop += TSPACE + avis.rcFrame.bottom*gwZoom/4; } else if (avis.fccType == streamtypeAUDIO) { LPWAVEFORMAT pwf = (LPWAVEFORMAT)abFormat; TCHAR *szFmt; if (pwf->wFormatTag == 1) { // PCM if (pwf->nChannels == 1) szFmt = TEXT("Format: Mono %dHz %dbit"); else szFmt = TEXT("Format: Stereo %dHz %dbit"); } else if (pwf->wFormatTag == 2) { // ADPCM if (pwf->nChannels == 1) szFmt = TEXT("Format: ADPCM Mono %dHz %dbit"); else szFmt = TEXT("Format: ADPCM Stereo %dHz %dbit"); } else { if (pwf->nChannels == 1) szFmt = TEXT("Format: Compressed Mono %dHz %dbit"); else szFmt = TEXT("Format: Compressed Stereo %dHz %dbit"); } PF2(szFmt,(int)pwf->nSamplesPerSec, (int)(pwf->nAvgBytesPerSec * 8 / pwf->nSamplesPerSec)); lAudioStart = lTime - muldiv32(rcC.right / 2, gdwMicroSecPerPixel, 1000); lAudioLen = 2 * (lTime - lAudioStart); // !!! Fix the SAMPLE field for short audio clips !!! //PF2("Sample:%ld %ld ", // AVIStreamTimeToSample(gapavi[i], lAudioStart), // AVIStreamTimeToSample(gapavi[i], lAudioLen)); /* Make rectangle to draw audio into */ rc.left = rcC.left; rc.right = rcC.right; rc.top = yStreamTop; rc.bottom = rc.top + AUDIOVSPACE * gwZoom / 4; PaintAudio(hdc, &rc, gapavi[i], lAudioStart, lAudioLen); yStreamTop += rc.bottom - rc.top; } else if (avis.fccType == streamtypeTEXT) { LONG lPos; int iLeft; lPos = AVIStreamTimeToSample(gapavi[i], lTime - muldiv32((rcC.right - rcC.left), gdwMicroSecPerPixel, 1000)); if (lPos < 0) lPos = 0; PatBlt(hdc, rcC.left, yStreamTop, rcC.right - rcC.left, TSPACE + TSPACE, WHITENESS); while (lPos < AVIStreamEnd(gapavi[i]) - 1) { // What pixel is it at this time? iLeft = (rcC.right + rcC.left) / 2 + (int) muldiv32(AVIStreamSampleToTime(gapavi[i], lPos) - lTime, 1000, gdwMicroSecPerPixel); if (iLeft >= rcC.right) break; AVIStreamRead(gapavi[i], lPos, 1, ach, sizeof(ach), &l, NULL); if (l) TextOut(hdc, iLeft, yStreamTop, ach, (int) l - 1); iLen = wsprintf(ach, TEXT("%ld"), lPos); TextOut(hdc, iLeft, yStreamTop + TSPACE, ach, iLen); #if 0 if (ghic[i]) { ICDrawBegin(ghic[i], 0, 0, hwnd, hdc, iLeft, yStreamTop, 100, 50, NULL, 0, 0, -1, -1, 1, 1); ICDraw(ghic[i], 0, NULL, ach, l, lPos); ICDrawEnd(ghic[i]); } #endif lPos += 1; } yStreamTop += TSPACE + TSPACE; } else { } yStreamTop += VSPACE; if (yStreamTop >= rcC.bottom) break; } EndPaint(hwnd,&ps); break; 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; case MM_WOM_OPEN: case MM_WOM_DONE: case MM_WOM_CLOSE: aviaudioMessage(hwnd, msg, wParam, lParam); break; } return DefWindowProc(hwnd,msg,wParam,lParam); } 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); return WinYield(); } LONG NEAR PASCAL AppCommand (hwnd, msg, wParam, lParam) HWND hwnd; unsigned msg; WPARAM wParam; LPARAM lParam; { OPENFILENAME ofn; TCHAR achFilter[128]; switch(GET_WM_COMMAND_ID(wParam, lParam)) { 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, gcpavi, gapavi, galpAVIOptions); break; case MENU_SAVEAS: case MENU_SAVERAW: case MENU_SAVESMALL: gachSaveFileName[0] = 0; /* prompt user for file to open */ ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = NULL; AVIBuildFilter(achFilter, sizeof(achFilter)/sizeof(TCHAR), TRUE); ofn.lpstrFilter = achFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = gachSaveFileName; ofn.nMaxFile = sizeof(gachSaveFileName)/sizeof(TCHAR); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; if (GET_WM_COMMAND_ID(wParam, lParam) == MENU_SAVEAS) ofn.lpstrTitle = TEXT("Save AVI File"); else if (GET_WM_COMMAND_ID(wParam, lParam) == MENU_SAVERAW) ofn.lpstrTitle = TEXT("Save Raw"); else if (GET_WM_COMMAND_ID(wParam, lParam) == MENU_SAVESMALL) ofn.lpstrTitle = TEXT("Save Small"); 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 (GetSaveFileName(&ofn)) { FARPROC lpfn = MakeProcInstance(SaveCallback, ghInstApp); if (lpfn) { DWORD fccHandler[MAXNUMSTREAMS]; int i; StartWait(); for (i = 0; i < gcpavi; i++) fccHandler[i] = galpAVIOptions[i]->fccHandler; // We only want to save the first video stream if (GET_WM_COMMAND_ID(wParam, lParam) == MENU_SAVESMALL) { SaveSmall(gpaviVideo, gachSaveFileName); EndWait(); break; } // !!! This won't take away audio compression !!! // We want to save raw -- don't use any video compression if (GET_WM_COMMAND_ID(wParam, lParam) == MENU_SAVERAW) for (i = 0; i < gcpavi; i++) galpAVIOptions[i]->fccHandler = 0; AVISaveV(gachSaveFileName, NULL, (AVISAVECALLBACK) lpfn, gcpavi, gapavi, galpAVIOptions); // !!! error check? // 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; case MENU_NEW: FreeAvi(hwnd); gachFileName[0] = TEXT('\0'); FixWindowTitle(hwnd); break; case MENU_OPEN: case MENU_ADD: gachFileName[0] = 0; /* prompt user for file to open */ ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = NULL; if (wParam == MENU_ADD) { ofn.lpstrTitle = TEXT("Merge With"); } else { ofn.lpstrTitle = TEXT("Open AVI"); } if (gachFilter[0] == TEXT('\0')) AVIBuildFilter(gachFilter, sizeof(gachFilter)/sizeof(TCHAR), FALSE); ofn.lpstrFilter = gachFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = gachFileName; ofn.nMaxFile = sizeof(gachFileName)/sizeof(TCHAR); 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 (GetOpenFileNamePreview(&ofn)) { InitAvi(hwnd, gachFileName, wParam); } break; 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; // // readly play the file, via MCI // case MENU_PLAY_STREAM: case MENU_PLAY_FILE: { TCHAR ach[80]; HWND hwndMci = MCIWndCreate(NULL, ghInstApp, MCIWNDF_SHOWNAME | MCIWNDF_SHOWMODE | WS_OVERLAPPEDWINDOW | WS_VISIBLE, NULL); if (hwndMci) { if (GET_WM_COMMAND_ID(wParam,lParam) == MENU_PLAY_FILE) wsprintf(ach, TEXT("AVIVideo!@%ld"), gpfile); else wsprintf(ach, TEXT("AVIVideo!@%ld"), gapavi[giCurrentStream]); MCIWndOpen(hwndMci, ach, 0); MCIWndPlay(hwndMci); } } break; // // Simulate playing the file. We just play the 1st audio stream and let // our main message loop scroll the video by whenever it's bored. // case MENU_PLAY: if (gfAudioFound) aviaudioPlay(hwnd, gpaviAudio, AVIStreamTimeToSample(gpaviAudio, GetScrollTime(hwnd)), AVIStreamEnd(gpaviAudio), FALSE); gfPlaying = TRUE; glPlayStartTime = timeGetTime(); glPlayStartPos = GetScrollTime(hwnd); break; // // Stop the play preview // case MENU_STOP: if (gfAudioFound) aviaudioStop(); gfPlaying = FALSE; break; #ifdef CLIPSTUFF case MENU_COPY: { PAVIFILE pf; AVIMakeFileFromStreams(&pf, gcpavi, gapavi); AVIPutFileOnClipboard(pf); AVIFileClose(pf); } break; case MENU_CFILE: AVIPutFileOnClipboard(gpfile); break; case MENU_PASTE: { PAVIFILE pf = NULL; AVIGetFromClipboard(&pf); if (pf) { DPF("Pasting file from clipboard....\n"); FreeDrawStuff(hwnd); InsertAVIFile(pf, hwnd, TEXT("Clipboard")); } else { DPF("Can't get file from clipboard....\n"); } break; } #endif } 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); va_end(va); MessageBox(NULL,ach,NULL, #ifdef BIDI MB_RTL_READING | #endif MB_OK|MB_ICONEXCLAMATION|MB_TASKMODAL); return FALSE; } /*----------------------------------------------------------------------------*\ | fDialog(id,hwnd,fpfn) | | | | Description: | | This function displays a dialog box and returns the exit code. | | the function passed will have a proc instance made for it. | | | | Arguments: | | id resource id of dialog to display | | hwnd parent window of dialog | | fpfn dialog message function | | | | Returns: | | exit code of dialog (what was passed to EndDialog) | | | \*----------------------------------------------------------------------------*/ BOOL fDialog(int id,HWND hwnd,FARPROC fpfn) { BOOL f; HANDLE hInst; hInst = GetWindowInstance(hwnd); fpfn = MakeProcInstance(fpfn,hInst); f = DialogBox(hInst,MAKEINTRESOURCE(id),hwnd,fpfn); FreeProcInstance (fpfn); return f; } /***************************************************************************** * * 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]; static BOOL fDebug = -1; va_list va; 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); // lstrcat(ach, "\r\n"); OutputDebugStringA(ach); } #endif // !!! function that makes DIBs half as big BOOL CrunchDIB( LPBITMAPINFOHEADER lpbiSrc, // BITMAPINFO of source LPVOID lpSrc, // input bits to crunch LPBITMAPINFOHEADER lpbiDst, // BITMAPINFO of dest LPVOID lpDst); // output bits to crunch // // Save a video stream into a new file, after calling CrunchDib on each frame... // void SaveSmall(PAVISTREAM ps, LPTSTR lpFilename) { PAVIFILE pf; PAVISTREAM psSmall = NULL; HRESULT hr; AVISTREAMINFO strhdr; BITMAPINFOHEADER bi; BITMAPINFOHEADER biNew; LONG l; LPVOID lpOld = NULL; LPVOID lpNew = NULL; AVIStreamFormatSize(ps, 0, &l); if (l > sizeof(bi)) return; l = sizeof(bi); hr = AVIStreamReadFormat(ps, 0, &bi, &l); if (bi.biCompression != BI_RGB) return; hr = AVIStreamInfo(ps, &strhdr, sizeof(strhdr)); hr = AVIFileOpen(&pf, lpFilename, OF_WRITE | OF_CREATE, NULL); if (hr != 0) return; biNew = bi; biNew.biWidth /= 2; biNew.biHeight /= 2; biNew.biSizeImage = ((((UINT)biNew.biBitCount * biNew.biWidth + 31)&~31) / 8) * biNew.biHeight; SetRect(&strhdr.rcFrame, 0, 0, (int) biNew.biWidth, (int) biNew.biHeight); hr = AVIFileCreateStream(pf, &psSmall, &strhdr); if (hr != 0) { goto exit; } hr = AVIStreamSetFormat(psSmall, 0, &biNew, sizeof(biNew)); if (hr != 0) { goto exit; } lpOld = GlobalAllocPtr(GMEM_MOVEABLE, bi.biSizeImage); lpNew = GlobalAllocPtr(GMEM_MOVEABLE, biNew.biSizeImage); if (!lpOld || !lpNew) { goto exit; } for (l = AVIStreamStart(ps); l < AVIStreamEnd(ps); l++) { hr = AVIStreamRead(ps, l, 1, lpOld, bi.biSizeImage, NULL, NULL); // !!! error check CrunchDIB(&bi, lpOld, &biNew, lpNew); hr = AVIStreamWrite(psSmall, l, 1, lpNew, biNew.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); // !!! error check } exit: if (lpOld) GlobalFreePtr(lpOld); if (lpNew) GlobalFreePtr(lpNew); if (psSmall) AVIStreamClose(psSmall); AVIFileClose(pf); }