/**************************************************************************** PROGRAM: demo.c PURPOSE: Windows applications to demonstrate use of WOLVES FUNCTIONS: WinMain() - calls initialization function, processes message loop InitApplication() - initializes window data and registers window InitInstance() - saves instance handle and creates main window MainWndProc() - processes messages About() - processes messages for "About" dialog box COMMENTS: Windows can have several copies of your application running at the same time. The variable hInst keeps track of which instance this application is so that processing will be to the correct window. ****************************************************************************/ #include "math.h" #include "windows.h" /* required for all Windows applications */ #include "demo.h" /* specific to this program */ HANDLE hInst; /* current instance */ /**************************************************************************** FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) PURPOSE: calls initialization function, processes message loop COMMENTS: Windows recognizes this function by name as the initial entry point for the program. This function calls the application initialization routine, if no other instance of the program is running, and always calls the instance initialization routine. It then executes a message retrieval and dispatch loop that is the top-level control structure for the remainder of execution. The loop is terminated when a WM_QUIT message is received, at which time this function exits the application instance by returning the value passed by PostQuitMessage(). If this function must abort before entering the message loop, it returns the conventional value NULL. ****************************************************************************/ int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) HANDLE hInstance; /* current instance */ HANDLE hPrevInstance; /* previous instance */ LPSTR lpCmdLine; /* command line */ int nCmdShow; /* show-window type (open/icon) */ { MSG msg; /* message */ BOOL bMsgAvail; short error; if (!hPrevInstance) /* Other instances of app running? */ if (!InitApplication(hInstance)) /* Initialize shared things */ return (FALSE); /* Exits if unable to initialize */ /* Perform initializations that apply to a specific instance */ if (!InitInstance(hInstance, nCmdShow)) return (FALSE); while (GetMessage(&msg, NULL, NULL, NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); /* Returns the value from PostQuitMessage */ } /**************************************************************************** FUNCTION: InitApplication(HANDLE) PURPOSE: Initializes window data and registers window class COMMENTS: This function is called at initialization time only if no other instances of the application are running. This function performs initialization tasks that can be done once for any number of running instances. In this case, we initialize a window class by filling out a data structure of type WNDCLASS and calling the Windows RegisterClass() function. Since all instances of this application use the same window class, we only need to do this when the first instance is initialized. ****************************************************************************/ BOOL InitApplication(hInstance) HANDLE hInstance; /* current instance */ { WNDCLASS wc; /* Fill in window class structure with parameters that describe the */ /* main window. */ wc.style = NULL; /* Class style(s). */ wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */ /* windows of this class. */ wc.cbClsExtra = 0; /* No per-class extra data. */ wc.cbWndExtra = 0; /* No per-window extra data. */ wc.hInstance = hInstance; /* Application that owns the class. */ wc.hIcon = LoadIcon(hInstance, "WipeIcon"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "DemoMenu"; /* Name of menu resource in .RC file. */ wc.lpszClassName = "DemoWClass"; /* Name used in call to CreateWindow. */ /* Register the window class and return success/failure code. */ return (RegisterClass(&wc)); } /**************************************************************************** FUNCTION: InitInstance(HANDLE, int) PURPOSE: Saves instance handle and creates main window COMMENTS: This function is called at initialization time for every instance of this application. This function performs initialization tasks that cannot be shared by multiple instances. In this case, we save the instance handle in a static variable and create and display the main program window. ****************************************************************************/ BOOL InitInstance(hInstance, nCmdShow) HANDLE hInstance; /* Current instance identifier. */ int nCmdShow; /* Param for first ShowWindow() call. */ { HWND hWnd; /* Main window handle. */ /* Save the instance handle in static variable, which will be used in */ /* many subsequence calls from this application to Windows. */ hInst = hInstance; /* Create a main window for this application instance. */ hWnd = CreateWindow( "DemoWClass", /* See RegisterClass() call. */ "LIVE WINDOW DEMO", /* Text for window title bar. */ WS_OVERLAPPEDWINDOW, /* Window style. */ CW_USEDEFAULT, /* Default horizontal position. */ CW_USEDEFAULT, /* Default vertical position. */ CW_USEDEFAULT, /* Default width. */ CW_USEDEFAULT, /* Default height. */ NULL, /* Overlapped windows have no parent. */ NULL, /* Use the window class menu. */ hInstance, /* This instance owns this window. */ NULL /* Pointer not needed. */ ); /* If window could not be created, return "failure" */ if (!hWnd) return (FALSE); /* Make the window visible; update its client area; and return "success" */ ShowWindow(hWnd, nCmdShow); /* Show the window */ UpdateWindow(hWnd); /* Sends WM_PAINT message */ return (TRUE); /* Returns the value from PostQuitMessage */ } /**************************************************************************** FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) PURPOSE: Processes messages MESSAGES: WM_COMMAND - application menu (About dialog box) WM_DESTROY - destroy window COMMENTS: To process the IDM_ABOUT message, call MakeProcInstance() to get the current instance address of the About() function. Then call Dialog box which will create the box according to the information in your wipedemo.rc file and turn control over to the About() function. When it returns, free the intance address. ****************************************************************************/ long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam) HWND hWnd; /* window handle */ unsigned message; /* type of message */ WORD wParam; /* additional information */ LONG lParam; /* additional information */ { #define TOTALSTEPS 60 #define DISPLAYTIME 60*3 #include "wolves.h" FARPROC lpProcAbout; /* pointer to the "About" function */ POINT pt; RECT Rect; VIDEOGRAB livewin1, livewin2, livewin3, livewin4; VIDEOPARM setdata,outdata,getdata; int VideoWidth,VideoHeight; unsigned int n, delay, mini; short error; float WidthInc, HeightInc, WidthVal, HeightVal; double centrex, centrey, width, height; switch (message) { case WM_COMMAND: /* message: command from application menu */ if (wParam == IDM_ABOUT) { lpProcAbout = MakeProcInstance(About, hInst); DialogBox( hInst, /* current instance */ "AboutBox", /* resource to use */ hWnd, /* parent handle */ lpProcAbout); /* About() instance address */ FreeProcInstance(lpProcAbout); break; } /* This is the code that handles the menu option RUN */ else if (wParam == IDM_RUN) { /* First we create our video window */ livewin1.hVidWnd = MTXCreateVideoWindow(); VideoWidth = GetSystemMetrics( SM_CXSCREEN ) ; VideoHeight= GetSystemMetrics( SM_CYSCREEN ) ; /* *--- get start position of window on screen. */ pt.x = 0; pt.y = 0; ClientToScreen( hWnd, (LPPOINT)&pt ); GetClientRect( hWnd, (LPRECT)&Rect ); /* Rect.left is now absolute pixel position of left of client area Rect.top is now absolute pixel position of top of client area Rect.right is now the width in pixels of our client area Rect.bottom is now the height in pixels of our client area */ Rect.left = pt.x; Rect.top = pt.y; /* by defining the destination of the grab as the total client area; and defining the source as the same width and height as the client area, we get the maximum portion of live video that will fit in the client area without minification. */ livewin1.XDst = Rect.left; livewin1.YDst = Rect.top; livewin1.DstWidth = Rect.right; livewin1.DstHeight = Rect.bottom; livewin1.XSrc = 0; livewin1.YSrc = 0; livewin1.SrcWidth = Rect.right; livewin1.SrcHeight = Rect.bottom; /* this will be a single grab of 120 consecutive fields. Hence the process will take about 2 sec. to complete*/ livewin1.FullMotion = FM_SINGLE; livewin1.Priority = DISPLAYTIME; // Now we do the actual grabbing error = MTXStartVideoGrab(&livewin1); // Now we will wait for the grab to stop getdata.hVidWnd = livewin1.hVidWnd; // checking on window #1 getdata.Name = VP_LIVEWINSTATE; // checking its status /* repeat getting the status until not single grabbing anymore */ do { error = MTXVideoParm (NULL, &getdata); // get the status } while (getdata.Value == LWS_SGLESTATE); /* by defining the destination of the grab as the total client area; and defining the source as the width and height of the source video. We get the maximum portion of live video that will fit in the client area while totally filling the client area with video. The minification factors in X and Y might be different, hence aspect ratio might not be one to one. */ livewin1.XDst = Rect.left; livewin1.YDst = Rect.top; livewin1.DstWidth = Rect.right; livewin1.DstHeight = Rect.bottom; livewin1.XSrc = 0; livewin1.YSrc = 0; livewin1.SrcWidth = VideoWidth; livewin1.SrcHeight = VideoHeight; /* this will be a single grab of 120 consecutive fields. Hence the process will take about 2 sec. to complete*/ livewin1.FullMotion = FM_SINGLE; livewin1.Priority = DISPLAYTIME; // Now we do the actual grabbing error = MTXStartVideoGrab(&livewin1); // Now we will wait for the grab to stop getdata.hVidWnd = livewin1.hVidWnd; // checking on window #1 getdata.Name = VP_LIVEWINSTATE; // checking its status /* repeat getting the status until not single grabbing anymore */ do { error = MTXVideoParm (NULL, &getdata); // get the status } while (getdata.Value == LWS_SGLESTATE); /* mini is an integer number representing the number of times the largest side of the client area fits into the total video source. */ mini=((VideoWidth/Rect.right) < (VideoHeight/Rect.bottom)) ? (VideoWidth/Rect.right):(VideoHeight/Rect.bottom); /* by defining the destination of the grab as the total client area; and defining the source as the width and height of the client area times the above mini factor. We get the maximum portion of live video that will fit in the client area while totally filling the client area with video and keeping a 1:1 aspect ratio. Hence we keep the minification factors in X and Y the same. */ livewin1.XDst = Rect.left; livewin1.YDst = Rect.top; livewin1.DstWidth = Rect.right; livewin1.DstHeight = Rect.bottom; livewin1.XSrc = 0; livewin1.YSrc = 0; livewin1.SrcWidth = Rect.right * mini; livewin1.SrcHeight = Rect.bottom * mini; /* this will be a single grab of 120 consecutive fields. Hence the process will take about 2 sec. to complete*/ livewin1.FullMotion = FM_SINGLE; livewin1.Priority = DISPLAYTIME; // Now we do the actual grabbing error = MTXStartVideoGrab(&livewin1); // Now we will wait for the grab to stop getdata.hVidWnd = livewin1.hVidWnd; // checking on window #1 getdata.Name = VP_LIVEWINSTATE; // checking its status /* repeat getting the status until not single grabbing anymore */ do { error = MTXVideoParm (NULL, &getdata); // get the status } while (getdata.Value == LWS_SGLESTATE); // using the WOLVES interface we can also control the display mode /* first we get current setting for Output mode and put it in outdata for later retore of the mode. */ outdata.hVidWnd = livewin1.hVidWnd; outdata.Name = VP_OUTMODE; error = MTXVideoParm (NULL,&outdata); /* now we set Output mode to INTERLACE */ setdata.hVidWnd = livewin1.hVidWnd; setdata.Name = VP_OUTMODE; setdata.Value = OM_INTERLACE; error = MTXVideoParm (&setdata,NULL); /* Now we will use a continuous grab window, and change it's parameters while it's grabbing. For this example we will start by changing the size of both source and destination at the same time. This will result in a wipe effect. While changing the width and height of the grab window, we will keep the as much of source video as possible in the destination window while maintaining correct aspect ratio. This is done by defining the source width and height as in above example. */ livewin1.XDst = Rect.left; livewin1.YDst = Rect.top; livewin1.XSrc = 0; livewin1.YSrc = 0; /* this will be a continuous grab window of 1 field*/ livewin1.FullMotion = FM_CONTINUOUS; livewin1.Priority = 1; // Now we WIPE from upper left corner in live /* the Width & Height increments are computed here to always get the total steps constant no matter what the total size of the destination window is. */ WidthInc = (float)(Rect.right)/TOTALSTEPS + 0.5; HeightInc = (float)(Rect.bottom)/TOTALSTEPS+ 0.5; WidthVal =0; HeightVal=0; for (n=0;nRect.right) WidthVal = Rect.right; if ((int)HeightVal>Rect.bottom) HeightVal = Rect.bottom; livewin1.SrcWidth = (int)WidthVal * mini; livewin1.DstWidth = (int)WidthVal; livewin1.SrcHeight= (int)HeightVal * mini; livewin1.DstHeight= (int)HeightVal; error = MTXStartVideoGrab(&livewin1); } /* NOTE: If we do not stop a FM_CONTINUOUS window with MTXStopVideoGrab,it will continue to display live window until we delete it with MTXDeleteVideoGrab or reprogram it with MTXStartVideoGrab. To demonstrate that here, we will do a for next loop doing nothing and we will see that the live window will continue to display live at the position of the last window programmed above. */ /* wait a little to see the effect */ for (delay=0;delay<100;delay++) { for (n=0;n<16000;) { n++; } } /* now we stop the grabbing process */ error = MTXStopVideoGrab (livewin1.hVidWnd); /* Now restore the display mode to the original mode. It's important to stop the video grab before switching display mode. */ error = MTXVideoParm (&outdata,NULL); /* Now we will use a continuous grab window, and change it's parameters while it's grabbing. For this example we will change the position of the source window plus the size of both source and destination at the same time. This will result in a slide effect. Again we will keep as much of source video as possible in the destination window while maintaining correct aspect ratio. This is done by defining the source width and height as in above example. */ livewin1.XDst = Rect.left; livewin1.YDst = Rect.top; /* this will be a continuous grab window of 1 field*/ livewin1.FullMotion = FM_CONTINUOUS; livewin1.Priority = 1; // Now we SLIDE from upper left corner & pause in live livewin1.Priority = 1; WidthVal =0; HeightVal=0; for (n=0;nRect.right) WidthVal = Rect.right; if ((int)HeightVal>Rect.bottom) HeightVal = Rect.bottom; livewin1.XSrc = Rect.right - (int)WidthVal; livewin1.YSrc = Rect.bottom - (int)HeightVal; livewin1.SrcWidth = (int)WidthVal * mini; livewin1.DstWidth = (int)WidthVal; livewin1.SrcHeight= (int)HeightVal * mini; livewin1.DstHeight= (int)HeightVal; error = MTXStartVideoGrab(&livewin1); } /* this time we stop the grabbing process while we get ready for next step */ error = MTXStopVideoGrab (livewin1.hVidWnd); // We will now demonstrate the possibility of more than one live window /* first we allocate space for 3 more live window */ livewin2.hVidWnd = MTXCreateVideoWindow(); livewin3.hVidWnd = MTXCreateVideoWindow(); livewin4.hVidWnd = MTXCreateVideoWindow(); /* we divide the user area in four equal rectangles */ width = (double)Rect.right / 2.0 -1; height = (double)Rect.bottom / 2.0 -1; centrex = (double)Rect.left + width; centrey = (double)Rect.top + height; /* we start with four live windows at same priority of 2. It is important to note that when displaying more than one video window using minification; you have to use a priority of at least 2. This is due to the impossibility to grab odd or even fields at certain vertical positions when using minification. Note that at boundaries where odd field can't be grabbed, you will be able to grab the even field; the reverse is also true. Hence a potential problem arises when using more than one video window under minification, for loosing fields that can't be grabbed at one of the video position. */ livewin1.Priority = 2; livewin2.Priority = 2; livewin3.Priority = 2; livewin4.Priority = 2; /* window 1 is position in top left corner of client area */ livewin1.XDst = Rect.left; livewin1.YDst = Rect.top; livewin1.DstWidth = width; livewin1.DstHeight = height; livewin1.XSrc = 0; livewin1.YSrc = 0; livewin1.SrcWidth = Rect.right * mini; livewin1.SrcHeight = Rect.bottom * mini; livewin1.FullMotion = FM_CONTINUOUS; /* window 2 is position in top right corner of client area */ livewin2.XDst = centrex; livewin2.YDst = Rect.top; livewin2.DstWidth = width; livewin2.DstHeight = height; livewin2.XSrc = 0; livewin2.YSrc = 0; livewin2.SrcWidth = Rect.right * mini; livewin2.SrcHeight = Rect.bottom * mini; livewin2.FullMotion = FM_CONTINUOUS; /* window 3 is position in bottom left corner of client area */ livewin3.XDst = Rect.left; livewin3.YDst = centrey; livewin3.DstWidth = width; livewin3.DstHeight = height; livewin3.XSrc = 0; livewin3.YSrc = 0; livewin3.SrcWidth = Rect.right * mini; livewin3.SrcHeight = Rect.bottom * mini; livewin3.FullMotion = FM_CONTINUOUS; /* window 4 is position in bottom right corner of client area */ livewin4.XDst = centrex; livewin4.YDst = centrey; livewin4.DstWidth = width; livewin4.DstHeight = height; livewin4.XSrc = 0; livewin4.YSrc = 0; livewin4.SrcWidth = Rect.right * mini; livewin4.SrcHeight = Rect.bottom * mini; livewin4.FullMotion = FM_CONTINUOUS; /* now we will use the fact that each time we start a video grab on a particular window, we are assured that at least one field will be grabbed to that window before we can delete it,stop it or restart it at a new location. */ /* We use the above fact for timing purpose here, by calling MTXStartVideoGrab 20 times in a row for the same window, we make sure we grab 20 field in that position before switching to the next step in this code. */ for (n=0;n<20;n++) { error = MTXStartVideoGrab(&livewin1); /* put window #1 alone */ } for (n=0;n<20;n++) { error = MTXStartVideoGrab(&livewin2); /* add window #2 */ } for (n=0;n<20;n++) { error = MTXStartVideoGrab(&livewin3); /* add window #3 */ } for (n=0;n<20;n++) { error = MTXStartVideoGrab(&livewin4); /* add window #4 */ } // Now we will demonstrate what can be done with priorities /* first get rid of both window #3 & #4 */ MTXStopVideoGrab(livewin3.hVidWnd); MTXStopVideoGrab(livewin4.hVidWnd); /* put priority of window #1 to 60 consecutive frames, keeping priority of window #2 at 2. This results in window #1 grabbing 60 fields in a row, then window #2 grabbing 2 fields. The resulting effect is that window #1 appears live while window #2 behaves in a stroboscopic grab way. Window #2 grabs a frame every seconds or so. */ livewin1.Priority = 60; error = MTXStartVideoGrab(&livewin1); /* wait a little to see the effect */ for (delay=0;delay<100;delay++) { for (n=0;n<32000;) { n++; } } error = MTXDeleteVideoWindow(livewin1.hVidWnd); error = MTXDeleteVideoWindow(livewin2.hVidWnd); error = MTXDeleteVideoWindow(livewin3.hVidWnd); error = MTXDeleteVideoWindow(livewin4.hVidWnd); break; } else /* Lets Windows process it */ { return (DefWindowProc(hWnd, message, wParam, lParam)); } case WM_DESTROY: /* message: window being destroyed */ PostQuitMessage(0); break; default: /* Passes it on if unproccessed */ return (DefWindowProc(hWnd, message, wParam, lParam)); } return (NULL); } /**************************************************************************** FUNCTION: About(HWND, unsigned, WORD, LONG) PURPOSE: Processes messages for "About" dialog box MESSAGES: WM_INITDIALOG - initialize dialog box WM_COMMAND - Input received COMMENTS: No initialization is needed for this particular dialog box, but TRUE must be returned to Windows. Wait for user to click on "Ok" button, then close the dialog box. ****************************************************************************/ BOOL FAR PASCAL About(hDlg, message, wParam, lParam) HWND hDlg; /* window handle of the dialog box */ unsigned message; /* type of message */ WORD wParam; /* message-specific information */ LONG lParam; { switch (message) { case WM_INITDIALOG: /* message: initialize dialog box */ return (TRUE); case WM_COMMAND: /* message: received a command */ if (wParam == IDOK /* "OK" box selected? */ || wParam == IDCANCEL) { /* System menu close command? */ EndDialog(hDlg, TRUE); /* Exits the dialog box */ return (TRUE); } break; } return (FALSE); /* Didn't process a message */ }