Chapter 2. Setting Up Your VL Application

Used in conjunction with your OCTANE Personal Video option, Video Library (VL) calls let you capture any part of the screen display and scale it down, output computer-generated graphics to videotape or the O2Cam digital camera, and output the input video source to the graphics monitor, to a video device such as a VCR, or both.

This chapter explains the first steps for creating video programs for OCTANE Personal Video:

The VL Programming Model

Syntax elements are as follows:

  • VL types and constants begin with uppercase VL; for example, VLServer

  • VL functions begin with lowercase vl; for example, vlOpenVideo()

Data transfers fall into two categories:

  • transfers involving memory (video to memory, memory to video), which require setting up a buffer

  • transfers not involving memory (such as video to screen and graphics to video), which do not require a buffer

For the two categories of data transfer, based on the VL programming model, the process of creating a VL application consists of these steps:

  1. Open a connection to the video daemon (vlOpenVideo()); if necessary, determine which device the application will use (vlGetDevice(), vlGetDeviceList()).

  2. Specify nodes on the data path (vlGetNode()).

  3. Create the path (vlCreatePath()).

  4. (Optional step) Add more connections to a path (vlAddNode()).

  5. Set up the hardware for the path (vlSetupPaths()).

  6. Specify path-related events to be captured (vlSelectEvents()).

  7. Set input and output parameters (controls) for the nodes on the path (vlSetControl()).

  8. For transfers involving memory, create a VL buffer to hold data for memory transfers (vlGetTransferSize(), dmBufferCreatePool() or vlCreateBuffer()).

  9. For transfers involving memory, register the buffer (vlRegisterBuffer()) or (video-to-memory only) vlDMBufferPoolRegister()

  10. Start the data transfer (vlBeginTransfer()).

  11. For transfers involving memory, get the data and manipulate it (DMbuffers: vlDMBufferGetValid(), vlGetActiveRegion(), dmBufferFree(); VL buffers: vlGetNextValid(), vlGetLatestValid(), vlGetActiveRegion(), vlPutFree()).

  12. Clean up (vlEndTransfer(), vlDeregisterBuffer(), vlDestroyPath(), dmBuffer() or vlDestroyBuffer(), vlCloseVideo()).

Performing Preliminary Steps

To build programs that run under VL, you must

  • install the dmedia_dev option

  • link with libvl.so

  • include vl.h and dev_evo.h

The client library is /usr/lib/libvl.so. The header files for the VL are in /usr/include/dmedia. The header file for the VL, vl.h, contains the main definition of the VL API and controls. The header file for OCTANE Personal Video is /usr/include/dmedia/vl_evo.h (linked to /usr/include/vl/dev_evo.h).


Note: When building a VL-based program, you must add -lvl to the linking command.


Opening a Connection to the Video Daemon

The first thing a VL application must do is open the device with vlOpenVideo(). Its function prototype is

VLServer vlOpenVideo(const char *sName) 

where sName is the name of the server to which to connect; set it to a NULL string for the local server. For example:

vlSvr = vlOpenVideo("")

Specifying Nodes on the Data Path

Use vlGetNode() to specify nodes; this call returns the node's handle. Its function prototype is

VLNode vlGetNode(VLServer vlSvr, int type, int kind, int number) 

where

VLNode 

is a handle for the node, used when setting controls or setting up paths

vlSvr 

names the server (as returned by vlOpenVideo())

type 

specifies the type of node:

  • VL_SRC: source

  • VL_DRN: drain

  • VL_DEVICE: device for device-global controls


    Note: If you are using VL_DEVICE, the kind should be set to 0.


kind 

specifies the kind of node:

  • VL_MEM: region of workstation memory

  • VL_SCREEN: workstation screen (source only)

  • VL_VIDEO: connection to a video device; for example, a video tape deck or O2Cam digital camera


Note: Appendix B, “OCTANE Personal Video Nodes and Their Controls,” gives full details of all OCTANE Personal Video nodes.


number 

is the number of the node in cases of two or more identical nodes, such as three video source nodes

To discover which node the default is, use the control VL_DEFAULT_SOURCE after getting the node handle the normal way. The default video source is maintained by the VL. For example:

vlGetControl(vlSvr, path, VL_ANY, VL_DEFAULT_SOURCE, &ctrlval);
nodehandle = vlGetNode(vlSvr, VL_SRC, VL_VIDEO, ctrlval.intVal);

In the first line above, the last argument is a struct that retrieves the value. Corresponding to VL_DEFAULT_SOURCE, the control VL_DEFAULT_DRAIN gets the default VL_SRC node.

Creating and Setting Up the Data Path

Once nodes are specified, use VL calls to

  • create the path

  • get the device ID

  • add nodes (optional step)

  • set up the data path

  • specify the path-related events to be captured

Creating the Path

Use vlCreatePath() to create the data path. Its function prototype is

VLPath vlCreatePath(VLServer vlSvr, VLDev vlDev
    VLNode src, VLNode drn) 

This code fragment creates a path if the device is unknown:

if ((path = vlCreatePath(vlSvr, VL_ANY, src, drn)) < 0) {
    vlPerror(_progName);
    exit(1);
}

This code fragment creates a path that uses a device specified by parsing a devlist:

if ((path = vlCreatePath(vlSvr, devlist[devicenum].dev, src,
    drn)) < 0) {
    vlPerror(_progName);
    exit(1);
}


Note: If the path contains one or more invalid nodes, vlCreatePath() returns VLBadNode.


Getting the Device ID

If you specify VL_ANY as the device when you create the path, use vlGetDevice() to discover the device ID selected. Its function prototype is

VLDev vlGetDevice(VLServer vlSvr, VLPath path)

For example:

devicenum = vlGetDevice(vlSvr, path);
deviceName = devlist.devices[devicenum].name;
printf("Device is: %s/n", deviceName);

Adding a Node

For this optional step, use vlAddNode(). Its function prototype is

int vlAddNode(VLServer vlSvr, VLPath vlPath, VLNodeId node)

where

vlSvr 

names the server to which the path is connected

vlPath 

is the path as defined with vlCreatePath()

node 

is the node ID

This example fragment adds a video source node and a device node:

vlAddNode(vlSvr, vlPath, src_vid); 
vlAddNode(vlSvr, vlPath, dev_node); 

Setting Up the Data Path

Use vlSetupPaths() to set up the data path. Its function prototype is

int vlSetupPaths(VLServer vlSvr, VLPathList paths,
      u_int count, VLUsageType ctrlusage,
      VLUsageType streamusage) 

where

vlSvr 

names the server to which the path is connected

paths 

specifies a list of paths you are setting up

count 

specifies the number of paths in the path list

ctrlusage 

specifies usage for path controls:

  • VL_SHARE: other paths can set controls on this node; this control is the desired setting for other paths, including vcp, to work


    Note: When using VL_SHARE, pay attention to events. If another user has changed a control, a VLControlChanged event occurs.


  • VL_READ_ONLY: controls cannot be set, only read; for example, this control can be used to monitor controls

  • VL_LOCK: prevents other paths from setting controls on this path; controls cannot be used by another path

  • VL_DONE_USING: the resources are no longer required; the application releases this set of paths for other applications to acquire

streamusage 

specifies usage for the data:

  • VL_SHARE: transfers can be preempted by other users; paths contend for ownership


    Note: When using VL_SHARE, pay attention to events. If another user has taken over the node, a VLStreamPreempted event occurs.


  • VL_READ_ONLY: the path cannot perform transfers, but other resources are not locked; set this value to use the path for controls

  • VL_LOCK: prevents other paths that share data transfer resources with this path from transferring; existing paths that share resources with this path will be preempted

  • VL_DONE_USING: the resources are no longer required; the application releases this set of paths for other applications to acquire

This example fragment sets up a path with shared controls and a locked stream:

if (vlSetupPaths(vlSvr, (VLPathList)&path, 1, VL_SHARE,
    VL_LOCK) < 0)
{
    vlPerror(_progName);
    exit(1);
}

Specifying the Path-Related Events to Be Captured

Use vlSelectEvents() to specify the events you want to receive. Its function prototype is

int vlSelectEvents(VLServer vlSvr, VLPath path, VLEventMask eventmask)

where

vlSvr 

names the server to which the path is connected

path 

specifies the data path.

eventmask 

specifies the event mask; Table 2-1 lists the possibilities

Table 2-1 lists and describes the VL event masks

Table 2-1. VL Event Masks

Symbol

Meaning

VLStreamBusyMask

Stream is locked

VLStreamPreemptedMask

Stream was grabbed by another path

VLStreamChangedMask

Video routing on this path has been changed by another path

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 trigger

VLDefaultSourceMask

Default source changed

 

For example:

vlSelectEvents(vlSvr, path, VLTransferCompleteMask); 

Event masks can be Or'ed; for example:

vlSelectEvents(vlSvr, path, VLTransferCompleteMask |
      VLTransferFailedMask);

For more details on VL event handling, see Chapter 7, “Event Handling.”