/************************************************************************ * * PROGRAM: SaveJpeg.c * * DESCRIPTION: Grabs a video Image every 5 seconds and save it to * a JPEG file. * * AUTHOR: Tom Bouril (August 1997) * *************************************************************************/ #include #include #include #include #include #include #include #include #include #include #define TIMER_MILLISECONDS 5000 /************************************************************************* * * DECLARE FUNCTION PROTOTYPES AND GLOBAL VARIABLES HERE. * *************************************************************************/ void SaveJpegImage(XtPointer, XtIntervalId *); void Mouse(XtPointer *); XtAppContext gAppContext; Widget gJpegWidget, videoWidget; static XrmOptionDescRec options[] = { {"-channel", "*videoIn.channel", XrmoptionSepArg, NULL}, {"-sourceWin", "*jpeg.sourceWin", XrmoptionSepArg, NULL}, }; /************************************************************************* * * FUNCTION: main() * * DESCRIPTION: Captures an image every X seconds (X specified in the call * to XtAppAddTimeOut()) and then saves that image to a * JPEG file. * * NOTE: It is NOT possible to do blind capture. In other words, the * image that you store must be visible on the monitor. The * video window canNOT be minimized or occluded behind another * window without obscuring the image that's saved... What * you see is what you get. * *************************************************************************/ void main(int argc, char **argv) { Widget top, jpegShell; Window windowID; top = XtAppInitialize(&gAppContext, "SaveJpeg", options, XtNumber(options), &argc, argv, NULL, (ArgList) NULL, 0); // Create a window to accept live video input. videoWidget = XtVaCreateManagedWidget("videoIn", xVideoInWidgetClass, top, XtNlive, True, NULL); // Add event handler to switch input sources for every mouse click. XtAddEventHandler(videoWidget, ButtonPressMask, False, Mouse, NULL); XtRealizeWidget(top); windowID = XtWindow(videoWidget); // Create jpegShell widget--used by a jpeg widget to compress video data. jpegShell = XtVaCreatePopupShell("jpegShell", topLevelShellWidgetClass, top, NULL); // Create a jpeg widget. gJpegWidget = XtVaCreateManagedWidget("jpeg", jpegWidgetClass, jpegShell, XtNsourceWin, windowID, NULL); XtRealizeWidget(jpegShell); // Calling XtPopup() will make the jpegShell window visible. XtPopup(jpegShell, XtGrabNone); // Calling XtPopdown() will make the jpegShell window invisible. // XtPopdown(jpegShell); // Set timer so SaveJpegImage() is called every TIMER_MILLISECONDS. XtAppAddTimeOut(gAppContext, TIMER_MILLISECONDS, SaveJpegImage, NULL); XtAppMainLoop(gAppContext); return; } /************************************************************************* * * FUNCTION: SaveJpegImage() * * DESCRIPTION: This function is called via the XtAppTimeOut() function. * This function must call XtAppAddTimeOut() to re-register * itself so it will get called again. When this function * is called, the captured image will be saved to a JPEG file. * * DANGER: There is a bug in the Parallax library for the XtNjfifOutputFile * function. The code below contains a fix that will override * any potential problems caused by that bug. Make certain this * bug-override gets included in any application code you write. * *************************************************************************/ void SaveJpegImage(XtPointer client_data, XtIntervalId *id) { char *Filename = "tom.jpg", // Name of file that will be saved. *AllocMem; static char *PtrAddr = 0; // STATIC VARIABLE--initialize to zero. // Grab new image to be saved to JPEG file. XtVaSetValues(gJpegWidget, XtNgetNewImage, TRUE, NULL); /*** THE FOLLOWING CODE OVERRIDES A POTENTIAL PROBLEM CAUSED BY A ***/ /*** BUG IN THE PARALLAX LIBRARY. DON'T UNDERSTAND IT--DO IT. ***/ // Allocate memory for filename to be used in XtVaSetValues() call. AllocMem = (char *) malloc(258); // PtrAddr is retained from last call to this function. PtrAddr will // get assigned the address of the filename string used by the // XtVaSetValues(gJpegWidget, XtNjfifOutputFile, PtrAddr, NULL) call. if (AllocMem == PtrAddr) { PtrAddr = AllocMem + 1; } else { PtrAddr = AllocMem; } strcpy(PtrAddr, Filename); // Set the compression ratio (Q-Factor) and save the JPEG image to file. // Q-Factor must be from 25 to 1000. XtVaSetValues(gJpegWidget, XtNqFactor, 50, XtNjfifOutputFile, PtrAddr, NULL); // Always free the memory allocated. free(AllocMem); /****** END OF PARALLAX BUG OVERRIDE *********************************/ /****** END OF PARALLAX BUG OVERRIDE *********************************/ // Re-register this timer callback procedure so it gets called again. XtAppAddTimeOut(gAppContext, TIMER_MILLISECONDS, SaveJpegImage, NULL); return; } /********************************************************************** * * FUNCTION: Mouse() * * DESCRIPTION: Every time a mouse button is pressed, this event * handler gets called and the input wire selected * is toggled. * **********************************************************************/ void Mouse(XtPointer *data) { static int Toggle = 0; if (Toggle == 0) { XtVaSetValues(videoWidget, XtNchannel, PLX_INPUT_0, XtNsignalFormat, PLX_COMP, XtNinstance, 0, XtNsignalStandard, PLX_NTSC, NULL); Toggle = 1; } else { XtVaSetValues(videoWidget, XtNchannel, PLX_INPUT_0, XtNsignalFormat, PLX_COMP, XtNinstance, 1, XtNsignalStandard, PLX_NTSC, NULL); Toggle = 0; } return; }