This document supplements the material in the "IRIS Media Libraries Programming Guide" (hereinafter, "the Guide"). It adds information about the VL that I think is missing or wrong in the Guide. It doesn't attempt to answer all remaining questions about the VL, or to be a complete reference. This is merely the information that I figured out while making InPerson work on vino, ev1, ev3, and sirius video for IRIX 5.3 and 6.2. Chris updated this document for mvp and IRIX 6.3. This information applies only to those VL video devices, and not to any other present or future VL video devices (it does not yet completely reflect cosmo2 and divo, for example).
This document does not represent SGI, and is not an official SGI publication. The entire contents of this document are my personal observations, and/or opinions, and all errors and opinions in it are mine alone. SGI makes no guarantees about anything in this document. Neither do I. You use it at your own risk. Additional disclaimers below.
Some topics NOT discussed in this page include:
The VL_SIZE control on the video source node is a read-only control. The x and y values returned by this control are affected by the setting of the VL_TIMING control on the video source node. The x and y values of this control are not, in general, affected by the settings of any controls in the memory drain node, including VL_ZOOM, VL_SIZE, and VL_CAP_TYPE.
The x component value of this control reveals the width, in pixels, of
the unzoomed, unclipped video input images (fields or frames). The
meaning of the y component value of the video source node's VL_SIZE
control depends on the video device.
On sirius, an application uses VL_PACKING on the memory node to specify the packing, and VL_FORMAT on the memory node to specify colorspace. If necessary, sirius will do colorspace conversion. Sirius is the only device where VL_FORMAT even applies to memory node.
On divo, an application uses VL_PACKING on the memory node to specify the packing, and VL_COLORSPACE on the memory node to specify colorspace. If necessary, divo will do colorspace conversion. This is a new API which should be inherited by all new VL devices from divo and beyond.
For complete information on pixel packings and colorspaces, check out The Pixel Rosetta Stone: Packings and Colorspaces.
The VL_PACKING_YVYU_422_8 packing is the only packing that is natively supported in hardware (requiring no software conversion) on all VL video devices. The packing always uses 4:2:2 sampling, and the default colorspace for this packing is always headroom-range. See The Pixel Rosetta Stone: Packings and Colorspaces for definitions of these terms.
On sirius, this control is read-only, and is permanently set to
VL_CAPTURE_NONINTERLEAVED. Each captured buffer contains exactly one
field, unclipped, unzoomed.
The possible values are:
On all devices except ev1, this setting of VL_CAP_TYPE will give you
one field in each entry of a VLBuffer. The data will always begin
with a dominant field (F1 unless otherwise specified by the video
device) and it will always alternate between F1 and F2 (see Definitions: F1/F2, Interleave, Field Dominance,
and More for definitions of dominance, F1, and F2). If the device
has to drop some data, it will drop both an F1 and an F2 (in some
order), so that the .../F1/F2/F1/F2/... ordering is maintained.
VL_RATE is in fields per second.
On ev1, each VLBuffer entry contains two fields butted up against one
another in memory, with the F1 field first in memory and then the F2
field. VL_RATE is in frames per second.
On devices which support it, this setting of VL_CAP_TYPE gives you
pairs of fields which have been weaved together in memory to form a
complete frame (television picture) from top to bottom. The F1 and F2
fields are placed according to the rules for the video standard being
used, as described in Definitions: F1/F2,
Interleave, Field Dominance, and More. VL_RATE is in frames per
second.
This setting is like VL_CAPTURE_NONINTERLEAVED except you only get F1
fields. VL_RATE is in frames per second.
This setting is like VL_CAPTURE_NONINTERLEAVED except you only get F2
fields. VL_RATE is in frames per second.
There is no single VL_CAP_TYPE that is available, and implemented in the
same way, on all VL video devices. VL_CAPTURE_NONINTERLEAVED is available
on all devices, but has different meanings on different platforms.
VL_CAPTURE_INTERLEAVED, VL_CAPTURE_EVEN_FIELDS, and VL_CAPTURE_ODD_FIELDS
are available and common to all VL video devices except sirius.VL_TIMING
On all VL video devices except sirius, the VL_TIMING control applies
only to the video (not memory) nodes. The timing on the video source
node is usually set through the Video Control Panel. With sirius
video, the VL_TIMING control must be set properly on the memory drain
node. An easy way to set the VL_TIMING value for the memory node is
to read the value of the VL_TIMING control from the video source node,
and then set that value into the VL_TIMING control for the memory
node.VL_CAP_TYPE
On all VL video devices except sirius, this control is settable by the
application. Its setting determines whether the images in the buffers
returned by the VL are individual fields, or interleaved frames, or
pairs of non-interleaved fields.
Vino has a bug that affects capturing with VL_CAPTURE_INTERLEAVED.
The first buffer returned after the call to vlBeginTransfer() may have
only one field in it. The other field may contain all zero values.
For continuous transfers, this may go unnoticed, but for
VL_TRANSFER_MODE_DISCRETE captures (e.g. of a single image), this will
often result in an image in which every other line is black, or green,
depending on the color space in use. A missing field can be detected
by examining the first pixel or two in several successive pixel rows.
The workaround for this problem is to examine the image for the
presence of one black field, and one non-black field, and recapturing
another buffer if one field is black. Another solution worth
exploring is to capture two buffers, instead of one, and then throw
the first one away. This might suffice.
VL_CAPTURE_NONINTERLEAVED (all devices except ev1 and sirius) | 525 | All multiples of 10 and 12 between 10 and 60 |
625 | All multiples of 10 between 10 and 50 | |
VL_CAPTURE_NONINTERLEAVED (ev1) | 525 | All multiples of 5 and 6 between 5 and 30 |
625 | All multiples of 5 between 5 and 25 | |
VL_CAPTURE_INTERLEAVED, VL_CAPTURE_EVEN_FIELDS, and VL_CAPTURE_ODD_FIELDS | 525 | All multiples of 5 and 6 between 5 and 30 |
625 | All multiples of 5 between 5 and 25 |
With sirius video, this control is read-only. Its value is determined by the setting of the VL_TIMING control on the memory node:
VL_CAPTURE_NONINTERLEAVED | 525 | 60 fields per second |
625 | 50 fields per second |
Vino's VL_RATE cannot be set to a value less than 5/1.
1/1, 1/2, 1/3 | Implemented in hardware, looks OK. |
1/4, 1/6 | Implemented partially in hardware, partially in software. Looks OK, but slower and uses roughly 10% of an R4600 CPU. |
1/5, 1/7, 1/8 | implemented in hardware. Looks bad. Green shift. |
ev1:
1/1, 1/2, 1/4, 1/8 | Works OK for vid-to-mem |
1/3, 1/5, 1/7 | Works only for vid-to-screen, not vid-to-mem, and only with VL_CAPTURE_INTERLEAVED. |
2/1, 4/1 | Works only for vid-to-screen, not vid-to-mem. |
sirius and ev3:
1/1 | sirius and ev3 don't zoom. |
Video Standard | vino F1 | vino F2 | ev1 F1 | ev1 F2 | mvp F1 | mvp F2 | ev3 F1 | ev3 F2 |
---|---|---|---|---|---|---|---|---|
525-line | 21 | 284 | 21 | 283 | 21 | 283 | ? | ? |
625-line | 23 | 336 | 23 | 336 | 23 | 336 | ? | ? |
This table uses the line numbers and definitions from Definitions: F1/F2, Interleave, Field Dominance, and More. Note that all the cases except for 525-line F2 fields with vino conform to the diagrams "analog 525, practical digital 525, analog 625, and digital 625" shown in that document.
On vino, ev1, mvp, and ev3, any other VL_OFFSET Y value (positive or negative) slides your buffer up or down the video signal by that many lines. The minimum allowed Y value is device-dependent, but is negative enough to pick up VITC on at least the higher of the recommended lines found in ANSI/SMPTE 12M.
On ev1, when you select VL_CAPTURE_NONINTERLEAVED, each of your buffers contains an F1 and an F2 field butted together. The Y coordinates of VL_OFFSET have strange units which behave like "picture lines" even though this doesn't make sense. Basically, if you would like to shift N lines, set VL_OFFSET's Y coordinate to 2*N.
This document does not cover what ev3's units are because we haven't tested it yet.
The VL imposes these requirements on the values of VL_OFFSET and VL_SIZE:
VL_OFFSET and VL_SIZE cannot be both set in one atomic operation. A change in either component of either control could violate one of the rules above (or below), especially after VL_ZOOM is set to a smaller fraction. It may be necessary to alternately and repeatedly set VL_OFFSET and VL_SIZE until no VLValueOutOfRange errors are reported. See vlSetControlLoop.txt for a code sample that does this.
Every VL video device places additional limitations on the range of acceptable values of VL_SIZE and VL_OFFSET. Each device has different limitations.
An interesting bug: After setting VL_SIZE and/or VL_OFFSET on an ev1 memory drain node, the vertical value read back from the VL_SIZE control is often (always?) one less than the value set into the VL_SIZE control, indicating that the image buffers will contain one less row of pixels than were requested. In this case, the actual size of the buffer returned by ev1 will usually contain the requested number of rows, one more than the value returned in the VL_SIZE control.
Sirius doesn't support preemption. ev1 ellows preemption in some "sync modes" but not in others. When preemption is not allowed, the VL behaves as if the path was in mode VL_LOCK instead of VL_SHARE; preemptions simply don't happen.
When preemption occurs, your program will receive a VlStreamPreempted event. This means the following things:
The VLStreamAvailable events create a race between the preempted
programs. The outcome of the race depends on the actions taken by the
programs, and also on the device's implementation. Generally, as long
as all the programs are attempting shared use of the path, the last
caller of vlSetupPaths() wins.
When a program receives the VLStreamAvailable event, to regain the
usage of the path's data stream, it should call vlSetupPaths(...,
VL_SHARE, VL_SHARE) again. This call to vlSetupPaths() to regain
access to the path's data stream can succeed or it can fail. The
VLStreamAvailable event does not guarantee that it will succeed.
Let's look at these cases separately.
If the call to vlSetupPaths() succeeds, the application should set all
the controls for the path to the values they had before it was
preempted. Your application, that is now regaining the use of the
stream, should not assume that the controls are as they were before
the preemption. The preemption caused the usage of the path's
controls to become VL_SHARE, so the preempting application could have
changed any or all of those controls.
Since preemption does not deregister or destroy the ring buffer used
by your path, you may resume usage of that same buffer, provided that
all the path's controls are returned to the same values they had
before the preemption (especially VL_SIZE and VL_PACKING). However,
you might want to be doubly sure that the ring buffer is empty before
restarting the transfer with a call to vlBeginTransfer().
If the call to vlSetupPaths() to regain access to the path's data
stream fails (returns a negative value), the path
should remain in the same mode in which it was before
the failed call to vlSetupPaths(). If your program hasn't changed the
path since it was preempted, and if the call to vlSetupPaths() failed
with vl error VLPathInUse, the path should still be in the mode in
which it was placed by the original preemption, namely as if
vlSetupPaths(..., VL_SHARE, VL_READ_ONLY) had been done on this path.
The path should continue to behave exactly as when it was preempted,
and another VLStreamAvailable should be generated, if and when the
path becomes available again.
A VL application that wishes to use the default input source node on a
given device calls vlGetNode(vlServer, VL_SRC, VL_VIDEO, VL_ANY).
Each device's default input source node may be changed via a control.
The Video Control Panel supports this, and is usually used to make
this choice. When the default input source node on any VL video
device is changed, (e.g. between a digital input source node and an
analog input source node), the VL sends a VLDefaultSource event to all
programs that have selected this event, regardless of whether they are
using the device whose default input changed, or another VL device.
Each video source node may serve multiple jacks. The choice of active
input jack on a given source node is done with some VL controls,
VL_FORMAT or VL_MUXSWITCH, as described in Choosing an Input Jack. A change in input
jack between jacks connected to the same video source node usually
results in a VLControlChanged event, not a VLDefaultSource event.
If you wish your application to track the default input node, you must
manually tear down and rebuild your video path each time you receive a
VLDefaultSource event, like this:
While the path's stream usage is in VL_READ_ONLY mode, a
VLStreamAvailable event should be generated when the data stream for
the selected path becomes available. That is, a program should be
able to put itself into a "voluntarily preempted" mode by putting the
path's stream usage is in VL_READ_ONLY mode. Whether this actually
works or not depends on the device, and on the OS release. It has
worked on ev1 at one time. sirius does not support putting a path
into VL_READ_ONLY mode. sirius also does not support preemption.
An application should be able to transition the stream usage of a path
from any one to any other of the four modes (VL_SHARE, VL_READ_ONLY,
VL_LOCK, VL_DONE_USING) as many times as it wishes. VL_DONE_USING is
not the "mode of no return". The principal difference between
VL_READ_ONLY and VL_DONE_USING seems to be the receipt of
VLStreamAvailable events in the VL_READ_ONLY mode.
Since sirius doesn't support VL_READ_ONLY, an application cannot use
VL_READ_ONLY to put itself into a mode where it will be notified when
another device has finished with the path. A sirius app has no choice
but to go to VL_DONE_USING mode when relenquishing the path, and to use
some external or manual means to know when to attempt to reaquire the path.
VLStreamAvailable
When all the nodes of a path that is being held in VL_READ_ONLY mode
are released, all programs holding the path in this mode will receive
a VLStreamAvailable event. This will happen when the program that was
last using the path called vlDestroyPath(), or released the path by
setting the stream usage to VL_READ_ONLY or VL_DONE_USING in a call to
vlSetupPaths().VLDefaultSource
Each video device may have multiple video source nodes, each of which
serves one or more physical input jacks on the video board. The VL
supports the concept of a "default input source node" or "default
video source node" for each device. There is no system-wide default
input source node, nor is there a default input device. An
application on a system with multiple video devices must choose one of
the devices according to its own methods.
If you wish to track VL_FORMAT and
VL_MUXSWITCH controls on a given node you are using, this may or may
not happen automatically depending on the device. See Choosing an Input Jack.
Other Miscellany
More About vlSetupPaths()
If a first attempt to gain access to a path via vlSetupPaths(...,
VL_SHARE, VL_SHARE) fails, and vlGetErrno() returns VLPathInUse, then
it should be possible to call vlSetupPaths(..., VL_SHARE,
VL_READ_ONLY) to put the path in the same state as it would be if it
had been preempted. Likewise, a program that wishes to voluntarily
release the path, and then later regain it, as if it had been
preempted should be able to put the path info VL_READ_ONLY mode.Premption vs. Cooperative Management
Since pre-emption and VL_READ_ONLY modes don't work on all platforms,
two or more programs that wish to cooperatively share the use of a VL
device might be better off to use their own protocol to pass ownership
of the device between them. The programs in the InPerson product used
this approach succesfully. IndyCam on ev1 Video Devices
IndyCam works on many of the boards in the ev1 family, as explained in
Taxonomy of the ev1 and cosmo1 Boards. The
images produced by IndyCam on ev1 tend to be very noisy in low light,
much more so than the images produced by IndyCam on vino. This noise
is seen as vertical and horizontal lines of gray in the image. Since
the output of IndyCam is digital, this noise is probably induced via
the power supplied to the IndyCam by the video board.