Chapter 5. Managing Connections

You can use the Video Library to set up complex paths in OCTANE Digital Video programs. Connections obey stream-usage levels set with vlSetupPaths(). Usage is drain-centric: the usage levels of the path(s) using the drain node serve as the usage level of the connection.

The functions vlSetConnection() and vlGetConnection() manipulate connections:

This chapter explains

Specifying Connectivity

The Video Library infers the connections on a path if vlBeginTransfer() is called and no drain nodes have been connected using vlSetConnection(). This situation simplifies application development for simple paths and supports the existing set of applications that do not use vlSetConnection()

Thus, the use of vlSetConnection() to specify the path connectivity is optional. The following rules are used in determining the connections:

  • For each internal node on the path, all unconnected input ports are connected to the first source node added to the path. Pixel ports are connected to pixel ports and alpha ports are connected to alpha ports.

  • For each drain node on the path, all unconnected input ports are connected to the first internal node placed on the path, if there is an internal node, or to the first source node placed on the path. Pixel ports are connected to pixel ports and alpha ports are connected to alpha ports.

Because existing connections are preserved, vlSetConnection() can be used to override part of the default routes, as long as all drain nodes remain unconnected.

The function prototype of vlSetConnection() is

int vlSetConnection(VLServer vlSvr, VLPath path, VLNode source_node, VLPort source_port, VLNode drain_node, VLPort drain_port, VLBoolean preempt)

where

vlSvr 

names the server to which the path is connected.

path 

specifies the data path whose connectivity is being changed.

source_node 

names the node that data will flow from. This is either a source or internal node.

source_port 

specifies the port on the source node to use.

drain_node 

specifies the node that data will flow to. This is either a drain or internal node.

drain_port 

specifies the port on the drain node to use.

preempt 

specifies whether other paths should be preempted (TRUE) or not (FALSE) in order to route the connection.

Connections must be specified only if

  • the path contains multiple internal nodes; in this case, the ordering of the internal nodes is ambiguous and may not be inferred properly by the Video Library

  • the default connections, described below, are not the ones that the application desires

  • the application wants to change a path's topology after the path has started transferring (note that the change in hardware route may cause a timing glitch in the video stream, depending on the device)

Connections are set up one at a time using vlSetConnection() and take effect either immediately or at the next vertical interval, depending on the device. In other words, if vlSetConnection() completes successfully, the hardware connection has been established.

Paths may be preempted in order to set a connection since scarce connector resources may be required to route a connection from the source (node, port) to the drain (node, port). The ability to preempt a path follows the rules for stream usage defined with vlSetupPaths(). The ability to set a connection, as opposed to only getting (retrieving) it, follows the rules for control usage.

This example fragment sets the blender node's foreground pixel input, that is, input A, to come from the framebuffer node output:

if (vlSetConnection(vlSvr, path, fb_node, VL_IMPACT_PORT_PIXEL_SRC, blender_node, VL_IMPACT_PORT_PIXEL_DRN_A, FALSE) < 0) 
{
    vlPerror(_progName);
    exit(1);
}

If vlSetConnection() returns with -1, an error has occurred. In addition to the standard error codes, the following have special meaning for vlSetConnection():

VLNoRoute 

No physical route could be found from the source to the drain.

VLPathInUse 

A physical route exists between the source and drain, but the required connector resources are in use. The application has requested that no paths be preempted by specifying FALSE as the preempt parameter, or another path has the resources locked.

Getting Connections

Use vlGetConnection() to retrieve the connections originating or terminating at a given (node, port). Its function prototype is

int vlGetConnection(VLServer vlSvr, VLPath path, VLNode node, VLPort port, VLNode *nodelist, VLPort *portlist, int *n) 

where

vlSvr  

specifies the server the application is connected to

path  

specifies the path whose connectivity is being checked

node  

specifies the node on the path

port  

specifies the port on the node

nodelist 

is an array of VLNode where the connected nodes will be returned

portlist  

is an array of VLPort where the connected ports are returned

*n 

specifies the size of the nodelist and portlist arrays; on exit, *n is updated to reflect the actual number of elements filled in

On successful exit, each (nodelist[i], portlist[i]) pair specifies one connection to (node, port). If port is a source port, then (nodelist[i], portlist[i]) specifies the drain ports it broadcasts to. If the port is a drain port, then (nodelist[0], portlist[0]) specifies the input. Because a drain port can have only one input, only the first entry is used.

If vlGetConnection() returns with -1, an error has occurred. In addition to the generic error codes, the error code VLNotEnoughSpace has special meaning to vlGetConnection(). It indicates that the array size, *n, is too small to contain the list of connections. *n is updated to reflect the required array length.

The fragment in Example 5-1 illustrates vlGetConnection().

Example 5-1. vlGetConnection() Example


/*
 * Connect to the video daemon
 */
svr = vlOpenVideo(““);

/*
  * Acquire video source and drain nodes.
  */
srcnode = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
drnnode = vlGetNode(svr, VL_DRN, VL_VIDEO, VL_ANY);

/*
 * Create a path with these nodes. 
 */
path = vlCreatePath(svr, VL_ANY, srcnode, drnnode);

/*
 * Connect the two nodes. Since this is a simple path with obvious
 * video routing, this step is optional. If the path contained
 * multiple internal nodes or the video route was not obvious, then 
 * we would need to explicitly state the connections.
 */
vlSetConnection(svr, path, srcnode, VL_IMPACT_PORT_PIXEL_SRC, drnnode,
VL_IMPACT_PORT_PIXEL_DRN, FALSE);

/*
 * Begin the transfer
 */
vlBeginTransfer(svr, path, 0, NULL);

Figure 5-1 diagrams the OCTANE Digital Video board architecture and shows which data can flow between blocks. An ellipse joining two links indicates that the two links can be used either as separate nodes or as a single dual-link mode.

Figure 5-1. Hardware Representation

Figure 5-1 Hardware Representation

Figure 5-2 is a software model of OCTANE Digital Video node connectivity. Each multiplexer (mux) is a full crossbar: any source can simultaneously broadcast to all destinations. An ellipse joining two links indicates that the two links can be used either as separate nodes or as a single dual-link mode.

Figure 5-2. Software Representation

Figure 5-2 Software Representation

The link with the alpha is called the pixel-alpha link, since it can carry pixel or alpha streams. See the VL_MGV_ALPHA_LUT control in “VL_DEVICE” in Appendix B for an explanation of this LUT.

  • At most two video streams can flow from the VBAR mux to the crosspoint mux, and at most two video streams can flow from the crosspoint mux to the VBAR mux. Attempts to set up paths that require more cross-mux streams result in VLPathInUse return codes, or in the path(s) using the links to be preempted.

  • Because only one link in each direction has a specific alpha LUT, at most one alpha stream can be routed into and at most on one alpha stream routed out of the crosspoint mux.

  • If a path uses a pixel-alpha link for a pixel stream and locks it (that is, sets stream usage to VL_LOCK), no alpha stream can be routed in that direction.

The allocation of the links is as follows:

  • If the target is a blender alpha input, the pixel-alpha link is allocated.

  • If the target is anything other than a blender alpha input, then the pixel link is used if it is available. Otherwise, the pixel-alpha link is used.

The dual-link video and memory nodes are composed of their single-link counterparts. Consequently, when a dual-link node is used, its single-link counterparts become unavailable. For example, when the dual-link video source is in use, video source 1 and video source 2 become unavailable.

Contention for the component single-link resources by the dual-link and single-link nodes follow normal preemption rules. A path using a dual-link node with stream usage VL_SHARE can be preempted by another path using one of its single-link constituents with stream usage VL_SHARE or VL_LOCK.

The CC1 memory source node and the framebuffer node share the same processing element. Consequently, only one can be in use at a time.

Unlike most sources, which feed directly into one of the muxes, the alpha from a screen source node can be fed only to blender alpha input. This restriction is enforced both by the VL_BLEND_A_ALPHA and VL_BLEND_B_ALPHA controls as well as by vlSetConnection().


Note: When a screen source is designated as source A alpha, the blender can extract alpha from it, because a screen source “contains” alpha. Otherwise, any other pixel stream is 4:2:2. If a source other than screen is designated as source A alpha, the blender uses the Y value as alpha and discards the U and V values.


Avoiding Dynamic Switching Problems

vlSetConnection() allows path topology to be changed while the path is transferring, with certain restrictions. This section explains what connections should and should not be switched during a transfer (dynamic switching). Possible failures include the following:

  • Picture glitch: Dynamic switching causes the output for one field to consist partly of the field before the switch (usually the top part), the field after the switch (usually the bottom part), and potentially a few garbage pixels at the transition. This glitch is due to the lack of vertical boundary resampling of the switching. However, there is no timing or synchronization glitch.

  • Timing glitch: Dynamic switching causes a temporary loss of synchronization. Picture monitors can tear, VTRs can slew, and downstream equipment hiccups in one way or another but eventually recovers. This glitch is unacceptable for any “live” situation.

In general, a glitch ripples downstream to other nodes. Changing video standards (PAL/NTSC or square pixel/CCIR601) always causes a timing glitch. Table 5-1 shows the effects of changing various controls. Glitches caused by changes in the video routing are explained more fully in the following section.

Table 5-1. Dynamic Effects of Various Video Data Path Controls

At Video Node

Timing Glitch Possible Causes

Picture Glitch Possible Causes

Causes No Glitch

Serial digital video output

Synchronizer bypass, horizontal phase, genlock reference sources

Crosspoint selection to video out; various blanking

Freeze

Serial digital video input

External interruption, autophase mode

Truncation or rounding

N/A

VGI1 memory drain

VBAR select to VGI1

Truncation or rounding

N/A

VGI1 memory source

VGI1 timing source

N/A

N/A

Blender and screen source

VBAR to crosspoint mux

Alpha LUT select, various blanking and rounding, internal crosspoint

Keyer/blender controls

As indicated in Figure 5-1, the OCTANE Digital Video option has timing restrictions for the crosspoint mux and for the VGI1 memory source.

Crosspoint Mux Timing Restrictions

The two outputs of the VBAR mux going into the crosspoint mux must be locked to within six pixels of each other if they are to be blended or displayed in windows B and C. To do this, make sure that the two video input channels are locked by enabling the input autophaser: set the VL_MGV_AUTO_PHASE to a value other than VL_MGV_AUTOPHASE_OFF. (Autophasing locks the video inputs to each other if, on input, their phase differences are not too great.)


Note: “VL_DEVICE” in Appendix B describes the use of these controls.

When one of the VBAR-to-crosspoint links is not in use, the following is done:

  • If the pixel-alpha link is not in use, it is set to the same input as the pixel link.

  • If the pixel link is not in use, it is set to the same input as the pixel-alpha link.

  • If neither links is in use, the output of the black generator is sent to both links.

This arrangement guarantees that if only one link is in use, the two links are locked. If two links are in use, then the application should ensure that the inputs are locked by enabling the input autophaser.


Note: The autophaser can affect only the two serial digital inputs.

Sending a video signal with bad timing into the crosspoint mux from the VBAR mux may cause the nodes attached to the crosspoint mux to operate inconsistently. These nodes derive master timing from the signal on the pixel-alpha link.

VGI1 Memory Source Timing Restrictions

The VGI1 memory sources derive their timing from the genlock source, or from an internal black generator if genlock is disabled. Consequently, changing controls associated with the genlock source may result in a transfer error on the memory node. Changing the autophase mode, for example, causes a timing glitch in the video stream.

Disconnecting the genlock source while a transfer is in progress causes the transfer to fail.

Using the Internal Video Sync Signal

Internal Video Sync refers to a synchronization signal produced or consumed by some audio and video devices. The purpose of the signal is to ensure that simultaneous audio and video signals are precisely synchronized.

This section explains

  • “Internal Video Sync Producers and Consumers”

  • “Setting the Internal Video Sync Signal Producer”

Internal Video Sync Producers and Consumers

While there may be multiple consumers of the Internal Video Sync signal, there can be only one Internal Video Sync producer (master of the Internal Video Sync line) in a system at any time. Table 5-2 lists Silicon Graphics options that produce or consume the Internal Video Sync signal.

Table 5-2. Internal Video Sync Signal Producers and Consumers

Producer

Consumer

Octane Digital Video

InfiniteReality™ graphics

Octane Compression

Radical Baseline Audio

Radical Audio

Radical Audio

DIVO digital video option for Origin2000™/Onyx2™

 

When the kernel initializes, it generates a list of Internal Video Sync devices but does not set any as the master of the Internal Video Sync line.

A producer must call ksync_attach() from its attach routine. This call adds the producer to the hardware graph and stores the arguments passed into the soft state on the new vertex. Producers must implement the KS_CONTROL_IOCTL call, which takes a single integer argument, 0 for off (KSYNC_OFF) and 1 for on KSYNC_ON).

A consumer need only call ksync_attach() and implement the KS_CONTROL_IOCTL. To handle Internal Video Sync disruption, a consumer should register a callback function in ksync_attach().

Setting the Internal Video Sync Signal Producer

Routines can use two Internal Video Sync calls, ksyncstat() and ksyncset(). ksyncstat() returns a list of Internal Video Sync-capable devices in the system. The devices are given as node names, not full pathnames; for example:

struct kstat_s ks_statbuf[64]
int i;

// Read system ksync configuration
ksyncstat( ks_statbuf, 64 );

// Find current Master
for( i=0; ks_statbuf[i].kName[0] != 0; i++ ) {
    if ( ks_statbuf[i].kFlags & KsyncIsProducer )
            
       // name of current master is in ks_statbuf[i].kName
}

// Search for potential producers..
for(i=0; ks_statbuf[i].kName[0] != 0; i++ ) {
    if( ks_statbuf[i].kFlags & KsyncProducerCapable ) {
            // found a producer, name is 
            // in ks_statbuf[i].kName
    }
    else if ( ks_statbuf[i].kFlags & KsyncConsumerCapable ) {
            // found a consumer, name is 
            // in ks_statbuf[i].kName
    }
}

The structure for ksyncstat() is as follows:

/*
       ** ksync flag values
       */

       #define KsyncIsProducer         0x1
       #define KsyncProducerCapable    0x2
       #define KsyncConsumerCapable    0x4
       #define KsyncActive             0x8

typedef struct {
           char        kName[ 64 ];
           int         kFlags;
       } kstat_t;

       int     ksyncstat( 
                       kstat_t         *buf, 
                       int             bufSz );        /* in bytes */

The buffer pointed to by buf is filled with as many kstat_t structures as there are Internal Video Sync devices on the system, or as many as the buffer holds. The element kName is the name of the device node on the hardware graph. Note that this name is the node name and not the full pathname.

ksyncset() causes a device to begin producing the Internal Video Sync signal. This call takes a string as an argument, for example:

ksyncset(“Digital Video”);

This example specifies a device. If another device is already producing the signal, that device immediately stops producing it and the device specified in the call begins producing it.

ksyncset(“None”);

Specifying None has the effect of turning off the Internal Video Sync signal. Also, if a device is specified that is not active in the system, Internal Video Sync signal generation is turned off and an error message is produced.

ksyncset(ks_statbuf[3].kName);

If the string corresponds to a string returned by ksyncstat(), and that name corresponds to a potential producer, that device becomes the new Internal Video Sync master. If there are no such correspondences, all producers are shut off. Using the string None (or any string that does not correspond to a potential producer) also shuts off all producers.

The Internal Video Sync feature is also implemented as a panel. This feature is incorporated into vcp and apanel as well, accessible in the Utilities menu.