AVIVIEW.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:65k
源码类别:
Windows编程
开发平台:
Visual C++
- /**************************************************************************
- *
- * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
- * PURPOSE.
- *
- * Copyright (C) 1993 - 1997 Microsoft Corporation. All Rights Reserved.
- *
- **************************************************************************/
- #define INC_OLE2
- #include <windows.h>
- #include <windowsx.h>
- #include <mmsystem.h>
- #include <memory.h>
- #include <commdlg.h>
- #include <vfw.h>
- #include "muldiv32.h"
- #include <mmreg.h>
- #include <msacm.h>
- #include "aviview.h"
- #include "audplay.h"
- #include "aviball.h"
- #define GlobalSizePtr(lp) GlobalSize(GlobalPtrHandle(lp))
- #define FIXCC(fcc) if (fcc == 0) fcc = mmioFOURCC('N', 'o', 'n', 'e');
- if (fcc == BI_RLE8) fcc = mmioFOURCC('R', 'l', 'e', '8');
- /*----------------------------------------------------------------------------*
- *----------------------------------------------------------------------------*/
- typedef LONG (PASCAL *LPWNDPROC)(HWND, UINT, WPARAM, LPARAM); // pointer to a window procedure
- /*----------------------------------------------------------------------------*
- *----------------------------------------------------------------------------*/
- static TCHAR gszAppName[]=TEXT("AVIView");
- static TCHAR gachFilter[512] = TEXT("");
- static HANDLE ghInstApp;
- static HWND ghwndApp;
- static HACCEL ghAccel;
- static HANDLE ghLib; // Handle to palmap32.dll
- static BOOL gbCanPalMap = FALSE; // Is palmap32.dll available?
- #define SCROLLRANGE 10000
- #define MAXNUMSTREAMS 50
- PAVIFILE gpfile; // the current file
- PAVISTREAM gapavi[MAXNUMSTREAMS]; // the current streams
- PGETFRAME gapgf[MAXNUMSTREAMS]; // data for decompressing
- // video
- HDRAWDIB ghdd[MAXNUMSTREAMS]; // drawdib handles
- 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
- int giFirstVideo; // index of gapavi for 1st Video stream
- #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;// scale for video
- TCHAR gachFileName[MAX_PATH] = TEXT("");
- TCHAR gachSaveFileName[MAX_PATH] = TEXT("");
- UINT gwZoom = 2; // one half zoom (divide by 4)
- AVICOMPRESSOPTIONS gaAVIOptions[MAXNUMSTREAMS];
- LPAVICOMPRESSOPTIONS galpAVIOptions[MAXNUMSTREAMS];
- HFONT hfontApp;
- TEXTMETRIC tm;
- BYTE abFormat[1024];
- LPVOID lpAudio; // buffer for painting
- int gnColours; // No of colours to remap palette to
- // !!! constants for painting
- #define VSPACE 8 // some vertical spacing
- #define HSPACE 4 // space between frames for video streams
- #define TSPACE 20 // space for text area about each stream
- #define AUDIOVSPACE 64 // height of an audio stream at X1 zoom
- /*----------------------------------------------------------------------------*
- *----------------------------------------------------------------------------*/
- #define GetScrollTime(hwnd)
- (LONG)(timeStart + muldiv32(GetScrollPos(hwnd, SB_HORZ), timeLength, SCROLLRANGE))
- #define SetScrollTime(hwnd, time) SetScrollPos(hwnd, SB_HORZ,
- (int)muldiv32((time) - timeStart, SCROLLRANGE, timeLength), TRUE)
- /*----------------------------------------------------------------------------*
- *----------------------------------------------------------------------------*/
- long PaintStuff(HDC hdc, HWND hwnd, BOOL fDrawEverything);
- LONG WINAPI AppWndProc (HWND hwnd, UINT uiMessage, WPARAM wParam, LPARAM lParam);
- int ErrMsg (LPTSTR sz,...);
- LONG PASCAL AppCommand(HWND hwnd, unsigned msg, WPARAM wParam, LPARAM lParam);
- BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
- BOOL CALLBACK GetNumberOfColorsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
- LONG GetNumberOfColors(PAVISTREAM ps);
- /*----------------------------------------------------------------------------*
- *----------------------------------------------------------------------------*/
- HCURSOR hcurSave;
- int fWait = 0;
- /*----------------------------------------------------------------------------*
- | StartWait()
- |
- | Start a wait operation... put up the hourglass if it's the first call.
- *----------------------------------------------------------------------------*/
- void StartWait()
- {
- if (fWait++ == 0) {
- SetCursor(LoadCursor(NULL,IDC_WAIT));
- }
- }
- /*----------------------------------------------------------------------------*
- | EndWait()
- |
- | 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);
- }
- }
- /*----------------------------------------------------------------------------*
- | WinYield()
- |
- | 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;
- }
- /*----------------------------------------------------------------------------*
- *----------------------------------------------------------------------------*/
- /*----------------------------------------------------------------------------*
- | FixScrollbars()
- |
- | When we load a file or zoom changes, we re-set the scrollbars.
- *----------------------------------------------------------------------------*/
- void FixScrollbars(HWND hwnd)
- {
- LONG lHeight = 0;
- RECT rc;
- HDC hdc;
- //
- // Pretend we're painting and count how many lines we needed
- //
- hdc = GetDC(NULL);
- ExcludeClipRect(hdc, 0, 0, 32767, 32767); // don't actually draw
- lHeight = PaintStuff(hdc, hwnd, TRUE);
- ReleaseDC(NULL, hdc);
- //
- // 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);
- }
- }
- /*----------------------------------------------------------------------------*
- | InitStreams()
- |
- | 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;
- DWORD dw;
- //
- // 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 = (DWORD)-1; // Default
- galpAVIOptions[i]->dwBytesPerSecond = 0;
- galpAVIOptions[i]->dwInterleaveEvery = 1;
- break;
- case streamtypeAUDIO:
- galpAVIOptions[i]->dwFlags |= AVICOMPRESSF_VALID;
- galpAVIOptions[i]->dwInterleaveEvery = 1;
- AVIStreamReadFormat(gapavi[i], AVIStreamStart(gapavi[i]),
- NULL, &lTemp);
- galpAVIOptions[i]->cbFormat = lTemp;
- if (lTemp)
- galpAVIOptions[i]->lpFormat = GlobalAllocPtr(GHND, lTemp);
- // Use current format as default format
- if (galpAVIOptions[i]->lpFormat)
- AVIStreamReadFormat(gapavi[i],
- AVIStreamStart(gapavi[i]),
- 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];
- giFirstVideo = i;
- //
- // Set the horizontal scrollbar scale to show every frame
- // of the first video stream exactly once
- //
- dw = (avis.rcFrame.right - avis.rcFrame.left) * gwZoom / 4 + HSPACE;
- gdwMicroSecPerPixel = muldiv32(1000000,
- avis.dwScale,
- dw * avis.dwRate);
- // Move one frame on the top video screen for each HSCROLL
- timehscroll = muldiv32(1000, avis.dwScale, avis.dwRate);
- }
- } else if (avis.fccType == streamtypeAUDIO) {
- //
- // If there are no video streams, we base everything on this
- // audio stream.
- //
- if (gpaviAudio == NULL && gpaviVideo == NULL) {
- // Show one sample per pixel
- gdwMicroSecPerPixel = muldiv32(1000000,
- avis.dwScale,
- avis.dwRate);
- // Move one sample per HSCROLL
- // Move at least enough to show movement
- timehscroll = muldiv32(1000, avis.dwScale, avis.dwRate);
- }
- //
- // Remember the first audio stream --- treat it specially
- //
- if (gpaviAudio == NULL)
- gpaviAudio = gapavi[i];
- }
- }
- timeLength = timeEnd - timeStart;
- if (timeLength == 0)
- timeLength = 1;
- // Make sure HSCROLL scrolls enough to be noticeable.
- timehscroll = max(timehscroll, timeLength / SCROLLRANGE + 2);
- SetScrollRange(hwnd, SB_HORZ, 0, SCROLLRANGE, TRUE);
- SetScrollTime(hwnd, timeStart);
- FixScrollbars(hwnd);
- }
- /*----------------------------------------------------------------------------*
- | FixWindowTitle()
- |
- | 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);
- }
- /*----------------------------------------------------------------------------*
- | FreeDrawStuff()
- |
- | Free up the resources associated with DrawDIB
- *----------------------------------------------------------------------------*/
- 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;
- }
- }
- SetScrollRange(hwnd, SB_HORZ, 0, 0, TRUE);
- gpaviVideo = gpaviAudio = NULL;
- }
- /*----------------------------------------------------------------------------*
- | FreeAvi()
- |
- | Free the resources associated with an open file.
- *----------------------------------------------------------------------------*/
- void FreeAvi(HWND hwnd)
- {
- int i;
- FreeDrawStuff(hwnd);
- AVISaveOptionsFree(gcpavi, galpAVIOptions);
- for (i = 0; i < gcpavi; i++) {
- AVIStreamRelease(gapavi[i]);
- }
- if (gpfile)
- AVIFileRelease(gpfile);
- gpfile = NULL;
- // Good a place as any to make sure audio data gets freed
- if (lpAudio)
- GlobalFreePtr(lpAudio);
- lpAudio = NULL;
- gcpavi = 0;
- }
- /*----------------------------------------------------------------------------*
- | InitBall()
- |
- | Open up our fake "ball" file as an installible stream hander
- *----------------------------------------------------------------------------*/
- void InitBall(HWND hwnd)
- {
- // close everything down
- FreeAvi(hwnd);
- // The NewBall() function creates a PAVISTREAM we can use as if it was
- // an AVI file.
- gapavi[0] = NewBall();
- if (gapavi[0])
- gcpavi = 1;
- lstrcpy(gachFileName, TEXT("BALL"));
- InitStreams(hwnd);
- FixWindowTitle(hwnd);
- }
- /*----------------------------------------------------------------------------*
- | InsertAVIFile()
- |
- | Does most of the work of opening an AVI file.
- *----------------------------------------------------------------------------*/
- void InsertAVIFile(PAVIFILE pfile, HWND hwnd, LPTSTR lpszFile)
- {
- int i;
- PAVISTREAM pavi;
- //
- // Get all the streams from the new file
- //
- for (i = gcpavi; i <= MAXNUMSTREAMS; i++) {
- if (AVIFileGetStream(pfile, &pavi, 0L, i - gcpavi) != AVIERR_OK)
- break;
- if (i == MAXNUMSTREAMS) {
- AVIStreamRelease(pavi);
- ErrMsg("Exceeded maximum number of streams");
- break;
- }
- gapavi[i] = pavi;
- }
- //
- // Couldn't get any streams out of this file
- //
- if (gcpavi == i && i != MAXNUMSTREAMS)
- {
- ErrMsg(TEXT("Unable to open %s"), lpszFile);
- if (pfile)
- AVIFileRelease(pfile);
- return;
- }
- gcpavi = i;
- if (gpfile) {
- AVIFileRelease(pfile);
- } else
- gpfile = pfile;
- FreeDrawStuff(hwnd);
- InitStreams(hwnd);
- FixWindowTitle(hwnd);
- }
- /*----------------------------------------------------------------------------*
- | InitAvi()
- |
- | Open up a file through the AVIFile handlers.
- *----------------------------------------------------------------------------*/
- void InitAvi(HWND hwnd, LPTSTR szFile, UINT wMenu)
- {
- HRESULT hr;
- PAVIFILE pfile;
- hr = AVIFileOpen(&pfile, szFile, 0, 0L);
- if (hr != 0)
- {
- ErrMsg(TEXT("Unable to open %s"), szFile);
- return;
- }
- if (wMenu == MENU_OPEN)
- FreeAvi(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;
- HDC hdc;
- #ifdef BIDI
- const DWORD dwExStyle = WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON;
- #else
- const DWORD dwExStyle = 0;
- #endif
- /* 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;
- }
- //
- // Must be called before using any of the AVIFile routines
- //
- AVIFileInit();
- hfontApp = GetStockObject(ANSI_VAR_FONT);
- hdc = GetDC(NULL);
- SelectObject(hdc, hfontApp);
- GetTextMetrics(hdc, &tm);
- ReleaseDC(NULL, hdc);
- ghwndApp=CreateWindowEx(dwExStyle,
- 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);
- ghLib = LoadLibrary(TEXT("palmap32.dll"));
- if (ghLib == NULL)
- gbCanPalMap = FALSE;
- else
- gbCanPalMap = TRUE;
- 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!
- FORWARD_WM_COMMAND(ghwndApp, MENU_STOP, NULL, 0, SendMessage);
- SetScrollTime(ghwndApp, l);
- InvalidateRect(ghwndApp, NULL, FALSE);
- UpdateWindow(ghwndApp);
- continue;
- }
- }
- WaitMessage();
- }
- // not reached
- return msg.wParam;
- }
- typedef BYTE * HPBYTE;
- typedef UNALIGNED short * HPSHORT;
- /*----------------------------------------------------------------------------*
- | PaintVideo()
- |
- | Draw a video frame in the specified rect.
- *----------------------------------------------------------------------------*/
- void PaintVideo(HDC hdc, RECT rcFrame, int iStream, LPBITMAPINFOHEADER lpbi, LONG lCurFrame, LONG lPos)
- {
- int iLen;
- char ach[200];
- RECT rc;
- COLORREF nCol;
- //
- // 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("%ld %ld.%03lds"),
- lCurFrame, lPos/1000, lPos%1000);
- }
- //
- // Before or after the movie (or read error) draw GRAY
- //
- else {
- if (gapgf[iStream])
- 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(' ');
- }
- //
- // 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;
- nCol = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
- ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE,
- &rc, ach, iLen, NULL);
- SetBkColor(hdc, nCol);
- }
- /*----------------------------------------------------------------------------*
- | PaintAudio()
- |
- | 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);
- //
- // 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 rectange - 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 = max(0, lWaveEndTime - lStart); // maybe nothing to draw!
- // left justify the legal samples in the rectange - don't stretch
- 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;
- //
- // 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))
- #define MONOBRUSH (GetSysColor(COLOR_BTNSHADOW))
- #define LEFTBRUSH (RGB(0,0,255))
- #define RIGHTBRUSH (RGB(0,255,0))
- #define HPOSBRUSH (RGB(255,0,0))
- //
- // 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
- //
- 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;
- //
- // !!! 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 - (int)muldiv32(b-0x80,(h/2),128);
- PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY);
- }
- else {
- i = y + (int)muldiv32(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++) {
- // Don't make any assumptions about INT size !
- // which byte of audio data belongs at this pixel?
- i = *((HPSHORT)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 - (int)muldiv32(b-0x80,(h/4),128);
- PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY);
- }
- else {
- i = y + (int)muldiv32(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 - (int)muldiv32(b-0x80,(h/4),128);
- PatBlt(hdc, rc.left+x, i, 1, y-i, PATCOPY);
- }
- else {
- i = y + (int)muldiv32(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++) {
- // Don't make any assumptions about INT size !
- i = *((HPSHORT)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++) {
- // Don't make any assumptions about INT size !
- i = *((HPSHORT)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
- }
- /*----------------------------------------------------------------------------*
- | PaintStuff()
- |
- | Paint the screen with what we plan to show them.
- *----------------------------------------------------------------------------*/
- long PaintStuff(HDC hdc, HWND hwnd, BOOL fDrawEverything)
- {
- int yStreamTop;
- TCHAR ach[400];
- int iFrameWidth, iLen;
- int n;
- int nFrames;
- LPBITMAPINFOHEADER lpbi;
- LONG lTime;
- LONG lSize = 0;
- LONG lAudioStart;
- LONG lAudioLen;
- RECT rcFrame, rcC;
- int i;
- LONG lFrame;
- LONG lCurFrame;
- HBRUSH hbr;
- RECT rc;
- COLORREF nCol;
- SelectObject(hdc, hfontApp);
- #define PRINT(sz)
- (nCol = SetBkColor(hdc, GetSysColor(COLOR_WINDOW)),
- TextOut(hdc, TSPACE, yStreamTop, sz, lstrlen(sz)),
- SetBkColor(hdc, nCol),
- 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);
- //
- // 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, lNextFmt, lPrevFmt, l;
- LONG lPos, lNextKey, lPrevKey, lNextAny, lPrevAny;
- AVIStreamInfo(gapavi[i], &avis, sizeof(avis));
- FIXCC(avis.fccHandler);
- FIXCC(avis.fccType);
- l = sizeof(abFormat);
- AVIStreamReadFormat(gapavi[i],0, &abFormat, &l);
- PF7(TEXT("Stream%d [%4.4hs/%4.4hs] Start: %ld Length: %ld (%ld.%03ld sec) "),
- i,
- (LPSTR)&avis.fccType,
- (LPSTR)&avis.fccHandler,
- AVIStreamStart(gapavi[i]),
- AVIStreamLength(gapavi[i]),
- AVIStreamLengthTime(gapavi[i]) / 1000,
- AVIStreamLengthTime(gapavi[i]) % 1000);
- lPos = AVIStreamTimeToSample(gapavi[i], lTime);
- AVIStreamSampleSize(gapavi[i], lPos, &lSize);
- lPrevKey = AVIStreamFindSample(gapavi[i], lPos, FIND_PREV|FIND_KEY);
- lPrevAny = AVIStreamFindSample(gapavi[i], lPos, FIND_PREV|FIND_ANY);
- lPrevFmt = AVIStreamFindSample(gapavi[i], lPos, FIND_PREV|FIND_FORMAT);
- lNextKey = AVIStreamFindSample(gapavi[i], lPos, FIND_NEXT|FIND_KEY);
- lNextAny = AVIStreamFindSample(gapavi[i], lPos, FIND_NEXT|FIND_ANY);
- lNextFmt = AVIStreamFindSample(gapavi[i], lPos, FIND_NEXT|FIND_FORMAT);
- PF5(TEXT("Pos:%ld Time:%ld.%03ld sec Size:%ld bytes %s "),
- lPos, lTime/1000, lTime%1000, lSize,
- (LPTSTR)(lPos == lPrevKey ? TEXT("Key") : TEXT("")));
- PF6(TEXT("PrevKey=%ld NextKey=%ld, PrevAny=%ld NextAny=%ld, PrevFmt=%ld NextFmt=%ld "),
- lPrevKey, lNextKey,
- lPrevAny, lNextAny,
- lPrevFmt, lNextFmt);
- //
- // Draw a VIDEO stream
- //
- if (avis.fccType == streamtypeVIDEO) {
- if (gapgf[i] == NULL)
- continue;
- lpbi = (LPBITMAPINFOHEADER)abFormat;
- FIXCC(lpbi->biCompression);
- //
- // display video format
- //
- // Video: 160x120x8 (cram)
- //
- PF4(TEXT("Format: %dx%dx%d (%4.4hs)"),
- (int)lpbi->biWidth,
- (int)lpbi->biHeight,
- (int)lpbi->biBitCount,
- (LPSTR)&lpbi->biCompression);
- //
- // 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);
- }
- //
- // 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..
- // (lFrame-n), (lFrame-(n-1)), ..., (lFrame), ...,
- // (lFrame+(n-1)), (lFrame+n)
- //
- lCurFrame = lFrame + n;
- //
- // what time is it at that frame? This number will be
- // printed underneath the frame
- //
- l = AVIStreamSampleToTime(gapavi[i], lCurFrame);
- } else { // NOT the first video stream
- //
- // What time is it at the left edge of the square
- // we'll draw? That's what frame we use.
- //
- if (n<0) {
- l = lTime - muldiv32(-n * iFrameWidth + HSPACE,
- gdwMicroSecPerPixel, 1000);
- }
- else {
- l = lTime + muldiv32(n * iFrameWidth,
- gdwMicroSecPerPixel, 1000);
- }
- //
- // What frame belongs to that time?
- //
- lCurFrame = AVIStreamTimeToSample(gapavi[i], l);
- //
- // what time is it at that frame? This number will
- // be printed underneath the frame
- //
- l = AVIStreamSampleToTime(gapavi[i], lCurFrame);
- }
- // !!!
- // 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;
- //
- // Figure out where to draw this 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 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, lCurFrame, l);
- }
- //
- // Move down to where we can draw the next stream
- //
- yStreamTop += (rcFrame.bottom - rcFrame.top) +
- TSPACE;
- }
- //
- // Draw an AUDIO stream
- //
- else if (avis.fccType == streamtypeAUDIO) {
- LPWAVEFORMAT pwf = (LPWAVEFORMAT)abFormat;
- TCHAR *szFmt;
- if (pwf->wFormatTag == 1) { // PCM
- if (pwf->nChannels == 1)
- szFmt = TEXT("Format: Mono %ldHz %dbit");
- else
- szFmt = TEXT("Format: Stereo %ldHz %dbit");
- }
- else if (pwf->wFormatTag == 2) { // ADPCM
- if (pwf->nChannels == 1)
- szFmt = TEXT("Format: ADPCM Mono %ldHz %dbit");
- else
- szFmt = TEXT("Format: ADPCM Stereo %ldHz %dbit");
- }
- else {
- if (pwf->nChannels == 1)
- szFmt = TEXT("Format: Compressed Mono %ldHz %dbit");
- else
- szFmt = TEXT("Format: Compressed Stereo %ldHz %dbit");
- }
- PF2(szFmt,(LONG)pwf->nSamplesPerSec,
- (int)((LONG)pwf->nAvgBytesPerSec / pwf->nSamplesPerSec /
- pwf->nChannels) * 8);
- //
- // Figure out which samples are visible
- //
- lAudioStart = lTime - muldiv32(rcC.right / 2,
- gdwMicroSecPerPixel, 1000);
- lAudioLen = 2 * (lTime - lAudioStart);
- //
- // Make rectangle to draw audio into
- //
- rc.left = rcC.left;
- rc.right = rcC.right;
- rc.top = yStreamTop;
- 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 += AUDIOVSPACE * gwZoom / 4;
- }
- 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) {
- LONG lStreamTime = AVIStreamSampleToTime(gapavi[i], lPos);
- // What pixel is it at this time?
- if (lStreamTime < lTime) { // pixel will be left of centre
- iLeft = (rcC.right + rcC.left) / 2 -
- (int) muldiv32(lTime - lStreamTime, 1000, gdwMicroSecPerPixel);
- }
- else { // pixel is at, or right of, centre
- iLeft = (rcC.right + rcC.left) / 2 +
- (int) muldiv32(lStreamTime - lTime, 1000, gdwMicroSecPerPixel);
- }
- if (iLeft >= rcC.right)
- break;
- AVIStreamRead(gapavi[i], lPos, 1, ach, sizeof(ach), &l, NULL);
- nCol = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
- if (l)
- TextOut(hdc, iLeft, yStreamTop, ach, (int) l - 1);
- iLen = wsprintf(ach, TEXT("%ld"), lPos);
- TextOut(hdc, iLeft, yStreamTop + TSPACE, ach, iLen);
- SetBkColor(hdc, nCol);
- lPos += 1;
- }
- yStreamTop += TSPACE + TSPACE;
- }
- yStreamTop += VSPACE;
- //
- // Give up once we're painting below the bottom of the window
- //
- if (!fDrawEverything && yStreamTop >= rcC.bottom)
- break;
- }
- //
- // How many lines did we draw?
- //
- return yStreamTop + GetScrollPos(hwnd, SB_VERT);
- }
- /*----------------------------------------------------------------------------*
- | 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 |
- | msg message number |
- | wParam message-dependent |
- | lParam message-dependent |
- | |
- | Returns: |
- | 0 if processed, nonzero if ignored |
- | |
- *----------------------------------------------------------------------------*/
- LONG WINAPI AppWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- PAINTSTRUCT ps;
- BOOL f;
- HDC hdc;
- RECT rc;
- LONG l;
- 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 = gfVideoFound || gfAudioFound;
- EnableMenuItem((HMENU)wParam, MENU_OPTIONS,f ? MF_ENABLED :
- MF_GRAYED);
- f = gcpavi > 0;
- EnableMenuItem((HMENU)wParam, MENU_SAVEAS, f ? MF_ENABLED :
- MF_GRAYED);
- EnableMenuItem((HMENU)wParam, MENU_NEW, f ? MF_ENABLED :
- MF_GRAYED);
- EnableMenuItem((HMENU)wParam, MENU_ADD, f ? MF_ENABLED :
- MF_GRAYED);
- f = (gpfile != 0) && gbCanPalMap && gfVideoFound;
- EnableMenuItem((HMENU)wParam, MENU_NEWPALETTE, 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;
- //
- // 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
- // an 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
- //
- 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
- AVIFileExit(); // shuts down the AVIFile system
- if (ghLib)
- FreeLibrary(ghLib);
- 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
- // !!! Assumes the first stream is video
- //
- if (ghdd[0] && (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);
- PaintStuff(hdc, hwnd, FALSE);
- 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 == (LONG)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);
- }
- /*----------------------------------------------------------------------------*
- | SaveCallback()
- |
- | Our save callback that prints our progress in our window title bar.
- *----------------------------------------------------------------------------*/
- BOOL PASCAL 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();
- }
- /*----------------------------------------------------------------------------*
- | AppCommand()
- |
- | Process all of our WM_COMMAND messages.
- *----------------------------------------------------------------------------*/
- LONG PASCAL AppCommand (HWND hwnd, unsigned msg, WPARAM wParam, LPARAM lParam)
- {
- switch(GET_WM_COMMAND_ID(wParam, lParam))
- {
- //
- // Our about box
- //
- case MENU_ABOUT:
- DialogBox(ghInstApp, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);
- break;
- //
- // 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,
- gcpavi, gapavi, galpAVIOptions);
- break;
- //
- // Use palmap to set the no of colours to save with
- //
- case MENU_NEWPALETTE:
- {
- HDC hdc;
- PAVISTREAM psMappedStream;
- PAVISTREAM psCurrent;
- AVISTREAMINFO avis;
- FARPROC lpfnAVICreateMappedStream;
- LPBITMAPINFOHEADER lpbi;
- #define AVICreateMappedStream 11 //Cardinal for procedure in palmap32.dll
- lpfnAVICreateMappedStream = GetProcAddress(ghLib,MAKEINTRESOURCE(AVICreateMappedStream));
- if (lpfnAVICreateMappedStream == NULL) {
- ErrMsg(TEXT("Unable to find AVICreateMappedStream in palmap32.dll"));
- gbCanPalMap = FALSE;
- }
- psCurrent = gapavi[giFirstVideo];
- AVIStreamInfo(psCurrent, &avis, sizeof(avis));
- if (avis.fccType != streamtypeVIDEO) {
- ErrMsg("Stream is not video!");
- break;
- }
- if (DialogBoxParam(
- ghInstApp,
- MAKEINTRESOURCE(IDD_NCOLORS),
- hwnd,
- GetNumberOfColorsDlgProc,
- (LPARAM)GetNumberOfColors(psCurrent))
- ) {
- StartWait();
- //
- // Find out how many colours they want to map it to
- //
- if (0 != (*lpfnAVICreateMappedStream)(&psMappedStream,
- psCurrent,
- gnColours)) {
- ErrMsg(TEXT("Can't map stream palette"));
- }
- else {
- gapavi[giFirstVideo] = psMappedStream;
- // We've just mapped this stream to a new palette
- // so we have to re-init the GetFrame stuff used
- // to draw this stream.
- // Kick start DrawDib to realize the new palette.
- //
- if (gapgf[giFirstVideo])
- AVIStreamGetFrameClose(gapgf[giFirstVideo]);
- gapgf[giFirstVideo] =
- AVIStreamGetFrameOpen(gapavi[giFirstVideo], 0);
- lpbi = AVIStreamGetFrame(gapgf[giFirstVideo], 0);
- DrawDibBegin(ghdd[giFirstVideo], NULL,
- lpbi->biWidth, lpbi->biHeight,
- lpbi, lpbi->biWidth, lpbi->biHeight, 0);
- hdc = GetDC(hwnd);
- DrawDibRealize(ghdd[giFirstVideo], hdc, FALSE);
- ReleaseDC(hwnd, hdc);
- }
- EndWait();
- }
- }
- break;
- //
- // Save all the open streams into a file
- //
- case MENU_SAVEAS:
- {
- OPENFILENAME ofn;
- gachSaveFileName[0] = 0;
- //
- // prompt user for file to save
- //
- ofn.lStructSize = sizeof(OPENFILENAME);
- ofn.hwndOwner = hwnd;
- ofn.hInstance = NULL;
- AVIBuildFilter(gachFilter, sizeof(gachFilter)/sizeof(TCHAR), TRUE);
- ofn.lpstrFilter = gachFilter;
- 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;
- ofn.lpstrTitle = TEXT("Save AVI File");
- 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)) {
- DWORD fccHandler[MAXNUMSTREAMS];
- int i;
- HRESULT hr;
- StartWait();
- for (i = 0; i < gcpavi; i++)
- fccHandler[i] = galpAVIOptions[i]->fccHandler;
- hr = AVISaveV(gachSaveFileName,
- NULL,
- (AVISAVECALLBACK) SaveCallback,
- gcpavi,
- gapavi,
- galpAVIOptions);
- if (hr != AVIERR_OK) {
- switch (hr) {
- case AVIERR_FILEOPEN:
- ErrMsg(TEXT("Overwriting an open AVI file is not possible"));
- break;
- default:
- 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();
- FixWindowTitle(hwnd);
- }
- }
- break;
- //
- // Close everything
- //
- case MENU_NEW:
- FreeAvi(hwnd);
- gachFileName[0] = TEXT(' ');
- FixWindowTitle(hwnd);
- break;
- //
- // Open a new file, or merge streams with a new file
- //
- case MENU_OPEN:
- case MENU_ADD:
- {
- OPENFILENAME ofn;
- 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(' '))
- 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 we've got a filename, go open it
- //
- if (GetOpenFileNamePreview(&ofn))
- 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;
- //
- // 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;
- }
- 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;
- }
- // Find the number of colours present in the stream palette
- LONG GetNumberOfColors(PAVISTREAM ps)
- {
- BITMAPINFOHEADER bmih;
- LONG cbFormat = sizeof(bmih);
- bmih.biClrUsed = 0;
- AVIStreamReadFormat(ps, 0, (LPVOID)&bmih, &cbFormat);
- return (LONG)bmih.biClrUsed;
- }
- /* GetNumberOfColorsDlgProc()
- *
- * Dialog Procedure for getting the no of colours the user wants in the palette
- *
- */
- BOOL CALLBACK GetNumberOfColorsDlgProc(
- HWND hwnd,
- UINT msg,
- WPARAM wParam,
- LPARAM lParam)
- {
- BOOL Translated;
- switch (msg) {
- case WM_COMMAND:
- switch (GET_WM_COMMAND_ID(wParam, lParam)) {
- case IDOK:
- gnColours = GetDlgItemInt(hwnd, IDC_NCOLORS, &Translated, FALSE);
- EndDialog(hwnd, TRUE);
- return TRUE;
- case IDCANCEL:
- EndDialog(hwnd, FALSE);
- }
- break;
- case WM_INITDIALOG:
- {
- SetDlgItemInt(hwnd, IDC_NCOLORS, lParam, FALSE);
- return TRUE;
- }
- }
- return FALSE;
- }
- /* AboutDlgProc()
- *
- * Dialog Procedure for the "about" dialog box.
- *
- */
- BOOL CALLBACK AboutDlgProc(
- HWND hwnd,
- UINT msg,
- WPARAM wParam,
- LPARAM lParam)
- {
- switch (msg) {
- case WM_COMMAND:
- EndDialog(hwnd, TRUE);
- return TRUE;
- case WM_INITDIALOG:
- if (gbCanPalMap) // Provide the user with
- ShowWindow(GetDlgItem(hwnd, IDS_PALETTE), SW_HIDE); // some information about
- else // whether palmap32.dll was
- ShowWindow(GetDlgItem(hwnd, IDS_PALETTE), SW_SHOW); // found.
- return TRUE;
- }
- return FALSE;
- }