Chapter 21. Handling IndigoVideo Events

Programs that use live video need to be notified when the setup or status of the IndigoVideo board changes. This chapter explains how to use either the X Window System or IRIS GL event mechanisms to provide your application with notification of status changes to the IndigoVideo board.

The X and IRIS GL event mechanisms are different, but they serve the same purpose. X event handling methods distinguish between video activity events and parameter change events; IRIS GL event handling methods lump these event classes together as a single pseudodevice. Wherever possible, X event handling should be used rather than IRIS GL event handling to provide greater portability and flexibility. See the IRIS IM Programming Guide, which you can read online using the IRIS InSight viewer, for more details about X event handling versus IRIS GL event handling.

In this chapter:

IndigoVideo Event Handling Basics

Programs receive video activity events only if they use live video, that is, only if they have executed an svBindWindow() or svBindGLWindow() call.

The four reasons for which the window system generates a video activity event are:

  • video started

    This event indicates that video has started in this window. It is generated when your program succeeds in turning on video using svBindWindow() or svBindGLWindow().

  • video stopped

    This event indicates that video has stopped in this window. It is generated when your program turns off video using svBindWindow() or svBindGLWindow() with an argument of SV_IN_OFF.

  • video busy

    Your program tried to turn on video in this window using svBindWindow() or svBindGLWindow(), but failed because another program had exclusive use of the IndigoVideo board.

  • video preempted

    Your program had video running in this window, but it was preempted by another program calling svBindWindow() or svBindGLWindow().

These event reasons are identified by global variables, listed in Table 21-1.

Table 21-1. Video Activity Event Variable Names

Reason

Variable Name

Video started

SvVideoStarted

Video stopped

SvVideoStopped

Video busy

SvVideoBusy

Video preempted

SvVideoPreempted

The five types of parameter change events are:

  • active attribute change

    This event indicates that a process has given up live video input; for example, by exiting, or by calling svBindWindow() or svBindGLWindow() with an argument of SV_IN_OFF.

  • signal change

    This event is generated whenever a process changes the broadcast standard and/or video mode by calling svSetParam(). Changing input sources can also generate this event, as IndigoVideo changes to the default broadcast standard and video mode for the new input source.

  • video frozen/unfrozen

    This event is generated whenever a process freezes or unfreezes video by calling svSetParam().

  • input source changed

    This event is generated whenever a process changes the input source by calling svSetParam().

  • other parameters changed

    This event is generated whenever a process changes any other variable by calling svSetParam().

These event reasons are identified by the global variables listed in Table 21-2.

Table 21-2. Video Parameter Change Event Variable Names

Reason

Variable Name

Active attribute

SvActiveAttribute

Signal change

SvEncodingAttribute

Video frozen/unfrozen

SvFreezeAttribute

Source change

SvSourceAttribute

Other parameter change

SvParamChangeAttribute


X Event Handling

To provide X event handling, you must include the appropriate X11 header files, and you must link your program with the X extensions library (-lXext), the X shared library (-lX11_s), and any X toolkits that you use.

Before your program can receive video-related X events, you must call the svSelectXEvents() function.

There are two types of video events, indicated by the following variables:

SvVideoActivityEventNumber 


Describes video events such as video starting, or video stopping, that affect only a specific window. The reason field of the video activity event is set to one of the values listed in Table 21-1. Only programs that use live video receive video activity events.

SvParamChangeEventNumber  


Describes parameter change events that apply to board settings. The attribute field of the param change event is set to one of the values listed in Table 21-2. In addition, the value field is set to the new value of the changed parameter (if applicable). In the case of SvEncodingAttribute events, the value field is set to one of the values listed in Table 21-3.

Table 21-3. Encoding Attribute Values

Variable

Broadcast Standard

Video Mode

SvNTSCComposite

NTSC

Composite

SvNTSCSVideo

NTSC

S-Video

SvPALComposite

PAL

Composite

SvPALSVideo

PAL

S-Video


Example 21-1 contains a listing of xevents.c, which demonstrates the use of X events. First, an event mask is set up, to establish interest in exposure, key, and video related events. A connection to the X server is established and a video device is opened with the proper window size for the signal being received. The program prints status messages about the events as they occur.

Example 21-1. X Event Handling for IndigoVideo events: xevents.c

/*
 * xevents.c
 *
 * This X11 program displays live video from the IndigoVideo board and shows
 * how to decode X11 video-related event information.
 *
 * Hit the escape or the 'q' keys to exit.
 */

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <svideo.h>             /* must be included after <X11/Xlib.h> */

/* We're interested in exposure, key and video-related events */
#define EVENTMASK   (ExposureMask|KeyPressMask|StructureNotifyMask)

main(int argc, char *argv[])
{
    Window          rootwin, win;
    Display        *display;
    XEvent          event;
    int             screen, width, height;
    SVhandle        V;
    long            param[2];

    /* Open connection to X server */
    if ((display = XOpenDisplay(0)) == NULL) {
        fprintf(stderr, "%s: cannot connect to X server", argv[0]);
        if (getenv("DISPLAY") == NULL)
            fprintf(stderr,
                    ", `DISPLAY' environment variable not set.\n");
        else
            fprintf(stderr, " %s\n", XDisplayName(0));
        exit(1);
    }

    /* Open video device */
    if ((V = svOpenVideo()) == NULL) {
        svPerror("open");
        exit(1);
    }
    /* Determine the window size from the signal standard */
    param[0] = SV_BROADCAST;
    svGetParam(V, param, 2);
    if (param[1] == SV_PAL) {
        width = SV_PAL_XMAX;
        height = SV_PAL_YMAX;
    } else {
        width = SV_NTSC_XMAX;
        height = SV_NTSC_YMAX;
    }
    printf("Default window size: %d by %d\n", width, height);

    /* Create appropriate-sized window */
    screen = DefaultScreen(display);
    rootwin = RootWindow(display, screen);
    win = XCreateSimpleWindow(display, rootwin, 100, 100, width, height,
               5, BlackPixel(display, screen), BlackPixel(display, screen));

    /* Set the window and icon names for the window manager before mapping it */
    XStoreName(display, win, "X Video Event Handler");
    XSetIconName(display, win, argv[0]);
    XSelectInput(display, win, EVENTMASK);
    XMapWindow(display, win);

    /* Associate video with window */
    if (svBindWindow(V, display, win, SV_IN_REPLACE) < 0) {
        svPerror("bindwindow");
        svCloseVideo(V);
        exit(1);
    }

    /* Receive video-related X events */
    svSelectXEvents(V, display);

    /* Event loop */
    while (1) {
        XNextEvent(display, &event);

        if (event.type == Expose) {
            printf("Expose event\n");
            if (svBindWindow(V, display, win, SV_IN_REPLACE) < 0) {
                svPerror("bindwindow");
                svCloseVideo(V);
                exit(1);
            }
        } else if (event.type == KeyPress) {    /* See if we're done */
            XKeyEvent      *kev = (XKeyEvent *) &event;
            KeySym          keysym;
            char            buf[4];

            XLookupString(kev, buf, 1, &keysym, 0);
            printf("Key pressed: '%c' (%d)\n", buf[0], buf[0]);
            if (buf[0] == 'Q' || buf[0] == 'q' || buf[0] == '\033') {
                printf("Quitting...\n");
                svCloseVideo(V);
                exit(0);
            }

        } else if (event.type == SvVideoActivityEventNumber) {
            SVvideoActivityEvent *ev = (SVvideoActivityEvent *) & event;

            if (ev->reason == SvVideoStarted) {
                printf("Video started\n");
            } else if (ev->reason == SvVideoStopped) {
                printf("Video stopped\n");
            } else if (ev->reason == SvVideoBusy) {
                printf("Video busy\n");
            } else if (ev->reason == SvVideoPreempted) {
                printf("Lost video\n");
            } else {
                printf("unknown video activity (%d)?\n", ev->reason);
            }

        } else if (event.type == SvParamChangeEventNumber) {
            SVparamChangeEvent *ev = (SVparamChangeEvent *) &event;

            if (ev->attribute == SvActiveAttribute) {
                /* value always 0 */
                if (svBindWindow(V, display, win, SV_IN_REPLACE) < 0) {
                    svPerror("bindwindow");
                    svCloseVideo(V);
                    exit(1);
                }
                printf("Active attribute: re-bound video\n");
            } else if (ev->attribute == SvEncodingAttribute) {
                printf("Encoding change: %d = ", ev->value);
                if (ev->value == SvNTSCComposite) {
                    printf("NTSC composite\n");
                } else if (ev->value == SvPALComposite) {
                    printf("PAL composite\n");
                } else if (ev->value == SvNTSCSVideo) {
                    printf("NTSC SVideo\n");
                } else if (ev->value == SvPALSVideo) {
                    printf("PAL SVideo\n");
                } else {
                    printf("?\n");
                }
            } else if (ev->attribute == SvFreezeAttribute) {
                printf("Freeze attribute: %s\n", ev->value ? "on" : "off");
            } else if (ev->attribute == SvSourceAttribute) {
                printf("Input source change: %d\n", ev->value + 1);
            } else if (ev->attribute == SvParamChangeAttribute) {
                printf("Parameter changed\n");  /* value always 1 */
            } else {
                printf("unknown param attribute (%d) ?\n", ev->attribute);
            }
        }
    }
}


IRIS GL Event Handling

Handling IRIS GL events is fairly simple. To receive video-related events, use the IRIS GL qdevice() function to queue events from the VIDEO pseudodevice, and use qread() to read the events from the queue.

When you get an event from the event queue using the IRIS GL qread() function, you must pass the function a pointer to a short integer. qread() returns a value indicating the device that generated the event, and fills in the reason for the event in the space pointed to by the argument. In the case of a video event, the reason will correspond to one of the constants listed in Table 21-1 or Table 21-2.

The event loop in Example 21-2 handles video events, printing a message when video is preempted by another process and rebinding the video when it is released by another process.

Example 21-2. Handling Video Events with IRIS GL Routines

long window_id, device;
SVhandle vidnode;
short reason;

/* ... */

qdevice(VIDEO);
qdevice(WINQUIT);
qdevice(WINSHUT);
while(TRUE) {
device=qread(&reason);
switch(device) {
case VIDEO: 
if (reason == SvVideoPreempted)
    printf("Lost video\n");
else if (reason == SvActiveAttribute) {
    svBindGLWindow(vidnode, window_id,
    SV_IN_REPLACE);
    printf("Re-bound video\n");
}
break;
case WINSHUT:
case WINQUIT:
exit(0);
}
}