The VL provides several ways of handling data stream events, such as completion or failure of data transfer, vertical retrace event, loss of the path to another client, lack of detectable sync, or dropped fields or frames. The method you use depends on the kind of application you're writing:
For a strictly VL application, use:
For an application that also accesses another program or device driver, or if you're adding video capability to an existing X or OpenGL application, set up an event loop in the main part of the application and use the IRIX file descriptor (FD) of the event(s) you want to add.
This chapter explains
querying VL events
creating a VL event loop
creating a main loop with callbacks
It concludes with an example illustrating a main loop and event loops.
General VL event handling routines are summarized in Table 4-1.
Table 4-1. VL Event Handling Routines
Routine | Use |
---|---|
Gets a file descriptor for a VL server | |
vlNextEvent() | Gets the next event; blocks until you get the next event from the queue |
vlCheckEvent() | Like a nonblocking vlNextEvent(), checks to see if you have an event waiting of the type you specify and reads it off the queue without blocking |
vlPeekEvent() | Copies the next event from the queue but, unlike vlNextEvent(), does not update the queue, so that you can see the event without processing it |
vlSelectEvents() | Selects video events of interest |
vlPending() | Queries whether there is an event waiting for the application |
vlEventToName() | Gets the character string with the name of the event; for example, to use in messages |
vlAddCallback() | Adds a callback; use for VL events |
vlRemoveCallback() | Removes a callback for the events specified if the client data matches that supplied when adding the callback |
vlRemoveAllCallbacks() | Removes all callbacks for the specified path and events |
vlCallCallbacks() | Creates a handler; used when creating a main loop or using a supplied, non-VL main loop |
vlRegisterHandler() | Registers an event handler; use for non-VL events |
vlRemoveHandler() | Removes an event handler |
The event type is an integer. vlEventToName() allows you to get the character string with the name of the event, so that you can use the event name, for example, in messages.
Table 4-2 summarizes VL event masks.
Symbol | Meaning |
---|---|
VLStreamBusyMask | Stream is locked |
VLStreamPreemptedMask | Stream was grabbed by another application |
VLAdvanceMissedMask | Time was already reached |
VLSyncLostMask | Irregular or interrupted signal |
VLSequenceLostMask | Field or frame dropped |
VLControlChangedMask | A control has changed |
VLControlRangeChangedMask | A control range has changed |
VLControlPreemptedMask | Control of a node has been preempted, typically by another user setting VL_LOCK on a path that was previously set with VL_SHARE |
VLControlAvailableMask | Access is now available |
VLTransferCompleteMask | Transfer of field or frame complete |
VLTransferFailedMask | Error; transfer terminated; perform cleanup at this point, including vlEndTransfer() |
VLEvenVerticalRetraceMask | Vertical retrace event, even field |
VLOddVerticalRetraceMask | Vertical retrace event, odd field |
VLFrameVerticalRetraceMask | Frame vertical retrace event |
VLDeviceEventMask | Device-specific event, such as a timing change on a node |
VLDefaultSourceMask | Default source changed |
Call vlGetFD() to get a file descriptor usable from select(2) or poll(2).
Call vlSelectEvents() to express interest in one or more event. For example:
vlSelectEvents(svr, path, VLTransferCompleteMask); |
Event masks can be Or'ed together. For example:
vlSelectEvents(svr, path, VLTransferCompleteMask | VLTransferFailedMask); |
Depending on whether you want to block processing or not, use vlNextEvent() (blocking) or vlCheckEvent() (nonblocking) to get the next event.
Use vlPeekEvent() to see what the next event in the queue is without removing it from the queue. For example, the part of the code that actually gets the event from the event loop uses vlNextEvent(), whereas another part of the code that just wants to know about it, for example, for priority purposes, uses vlPeekEvent().
You can set an event loop to run until a specific condition is fulfilled. The routine vlSelectEvents() allows you to specify which event the application will receive.
Using an event loop requires creating an event mask to specify the events you want. The VL event mask symbols are combined with the bitwise OR operator. For example, to set an event mask to express interest in either transfer complete or control changed events, use:
VLTransferCompleteMask | VLControlChangedMask |
To create an event loop, follow these steps:
Define the event; for example:
VLEvent ev; |
Set the event mask; for example:
vlSelectEvents(vlServer, path, VLTransferCompleteMask | VLControlChangedMask) |
Block on the transfer process until at least one event is waiting:
for(;;){ vlNextEvent(vlServer, &ev); |
Create the loop and define the choices; for example:
switch(ev.reason){ case VLTransferComplete: … break; case VLControlChanged: … break; } } |
vlMainLoop() is provided as a convenience routine and constitutes the main loop of VL applications. This routine first reads the next incoming video event; it then dispatches the event to the appropriate registered procedure. Note that the application does not return from this call.
Applications are expected to exit in response to some user action. There is nothing special about vlMainLoop(); it is simply an infinite loop that calls the next event and then dispatches it. An application can provide its own version of this loop, for example, to test a global termination flag or to test that the number of top-level widgets is larger than zero before circling back to the call to the next event.
To specify callbacks, that is, routines which are called when a particular VL event arrives, use vlAddCallback(). Its function prototype is:
int vlAddCallback(VLServer vlServer, VLEvent * event, void * clientdata, VLEventMask events, VLCallbackProc callback, void *clientData) |
Example 4-1 illustrates the use of vlAddCallback().
Example 4-1. Using VL Callbacks
main() { … /* Set up the mask for control changed events and Stream preempted events */ if (vlSelectEvents(vlSvr, vlPath, VLTransferComplete | VLStreamPreemptedMask)) doErrorExit(“select events”); /* Set ProcessEvent() as the callback for VL events */ vlAddCallback(vlSvr, vlPath, VLTransferCompleteMask | VLStreamPreemptedMask, ProcessEvent, NULL); /* Start the data transfer immediately (i.e. don't wait for trigger) */ if (vlBeginTransfer(vlSvr, vlPath, 0, NULL)) doErrorExit(“begin transfer”); /* Get and dispatch events */ vlMainLoop(); } /* Handle VL events */ void ProcessEvent(VLServer svr, VLEvent *ev, void *data) { switch (ev->reason) { case VLTransferComplete: /* Get the valid video data from that frame */ dataPtr = vlGetActiveRegion(vlSvr, transferBuf, info); /* Done with that frame, free the memory used by it */ vlPutFree(vlSvr, transferBuf); frameCount++; break; case VLStreamPreempted: fprintf(stderr, “%s: Stream was preempted by another Program\n”, _progname); docleanup(1); break; default: break; } } |
Delete a callback with vlRemoveCallback() or vlRemoveAllCallbacks(). Their function prototypes are:
int vlRemoveCallback(VLServer vlServer, VLPath * path, VLEventMask events, VLCallbackProc callback, void *clientData) int vlRemoveAllCallbacks(VLServer vlServer, VLPath * path, VLEventMask events) |
The functions vlAddHandler() and vlRemoveHandler() are analogous to vlAddCallback() and vlRemoveCallback(), respectively. Use them for non-VL events.
In /usr/people/4Dgifts/examples/dmedia/video/vl, the example program eventex.c illustrates how to create a main loop and event loops.
Caution: To simplify the code, this example does not check returns. You should, however, always check returns. |