Video Library (VL) calls let you perform video teleconferencing, blend computer-generated graphics with frames from videotape or any video source, and output the input video source to the graphics monitor, to a video device such as a VCR, or both.
This chapter explains the basics of creating video programs for OCTANE Compression:
The Video Library provides a software interface to the OCTANE Compression board, enabling applications to
display live video in a window
capture live video in system memory
encode graphics to video in real time
produce high-quality full-rate video output
The Video Library (VL) is a collection of device-independent and device-dependent C language calls for Silicon Graphics workstations equipped with video options. The VL provides generic video tools, including simple tools for importing and exporting digital data to and from Silicon Graphics systems, as well as to and from third-party video devices that adhere to the Silicon Graphics architectural model for video devices. Video tools are described in the Media Control Panels User's Guide, which you can view using the IRIS InSight™ viewer; similar applications are supplied in source-code form as examples in the directories /usr/share/src/dmedia/video/vl and /usr/share/src/dmedia/video/vl/OpenGL).
The VL works with other Silicon Graphics libraries, such as OpenGL®. The VL does not depend on the X Window System™, but you can use X Window System libraries or toolkits to create a windowing interface.
The VL allows programs to get events 60 times per second on a quiescent system; it also enables programs to share resources or to gain exclusive use of resources. It supports input and output of video data to or from locked-down memory at the nominal frame rate. The VL provides an API that enables applications to capture or play back video from system memory.
The OCTANE Compression board software includes a graphical user interface, /usr/sbin/vcp, that makes it convenient to access VL capabilities.
This section explains
VL system software architecture
VL architectural model of video devices
OCTANE Digital Video formats
This section describes features of these VL system components and tools:
video daemon
generic video tools
library and header files
Figure 3-1 diagrams the interaction between the VL, the video daemon, the kernel, the hardware, and the X Window System server.
The VL communicates with the IRIX kernel for device initialization, vertical retrace, setup, and maintenance of any device-supported direct memory access (DMA). See Chapter 1 of the Digital Media Programming Guide for more information on interfacing to other libraries.
Besides these components, the VL includes a collection of applications that support device configuration and control setting and retrieval, generic tools that display video on a workstation, and video control panels.
The video daemon /usr/etc/videod, which has device-dependent and device-independent portions, handles video device management and status information.
Management that the video daemon performs includes
multiple client access to multiple devices
The library supports connections from multiple client applications and manages their access to a limited number of video devices.
dispatching events
As events are handled and noted by devices, the daemon notifies applications that have expressed interest in those events.
handling events
As events are generated by the various devices, the daemon initiates any action required by an event before it hands the event off to interested applications.
maintaining exclusive use
Types of data or control usage for video clients in a Video Library application are Done Using, Read-only, Lock, and Shared. These usage levels apply only to write access on controls, not read access. Any application can open and read the control's values at any time.
client cleanup on exit
When a client exits or is terminated abnormally, its connection to the daemon is broken; the daemon performs any cleanup required of the system. Any exclusive-use modes that have been set are cleared; interested clients are notified that the device is no longer in exclusive use. Controls set by the client might persist, but are not guaranteed to remain after the client closes the connection.
Status information for which the video daemon is responsible includes
system status of video devices
The video devices installed in a system can be queried as to availability and control status.
video positioning (offset) information
control setting and retrieval
Device-independent and device-dependent controls are set and retrieved through the video daemon.
The generic video tools include
The vlinfo, vidtomem, and memtovid tools are command-line tools. In addition to their reference pages, these tools have explanations in the Media Control Panels User's Guide. Similar applications are supplied in source-code form as examples in the directories /usr/share/src/dmedia/video/vl and /usr/share/src/dmedia/video/vl/OpenGL).
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 files for OCTANE Compression are
/usr/include/dmedia/dev_mgv.h (linked to /usr/include/vl/vl_mgv.h)
/usr/include/dmedia/dev_impact.h (linked to /usr/include/vl/vl_impact.h)
/usr/include/dmedia/dev_mgc.h (linked to /usr/include/vl/vl_mgc.h), which is the header file for OCTANE Compression
/usr/include/dmedia/vl_impact.h (linked to /usr/include/vl/dev_impact.h), which contains definitions common to the OCTANE Digital Video and OCTANE Compression devices
The VL recognizes these classes of objects:
devices, each including sets of nodes
A video device can be internal, such as the OCTANE Digital Video board, or external, such as a videotape recorder connected to the OCTANE Digital Video board.
ports, the entities on nodes that produce or consume video data
controls, or parameters, that modify how data flows through nodes; for example:
video device parameters, such as blanking width, gamma value, horizontal phase, sync source
video data capture parameters
blending parameters
buffers, for sending frame data to and receiving frame data from host memory; the VL buffers contain a number of blocks; each with a pointer, a size, and pointers to the head (oldest) and tail (newest) valid data
Central concepts for VL are node, path, and port.
The node is an endpoint or internal processing element of the path, such as a video source like a VTR, video drain (such as to the OCTANE screen), a device (video), or the blender in which video sources are combined for output to a drain.
The path is an abstraction for a way of moving data around. A path is a set of nodes with video routes (connections) between the ports on the nodes. A path defines the useful connections between video sources and video drains. Figure 3-2 shows a simple path in which a frame from a videotape is displayed in a workstation window.
Figure 3-3 shows a more complex path with two video sources: a frame from a videotape and a computer-generated image are blended and output to a workstation window. This path is set up in stages.
The port is an entity on a node that produces or consumes video data.
Most nodes have only one port, such as the video in or video out nodes. Each internal node has at least two ports, input (drain) and output (source). The blend node has several ports (A alpha in, A pixel in, B alpha in, B pixel in, pixel out, alpha out).
Ports have several attributes:
link type: single-link or dual-link
data type: alpha, pixel, or pixel-alpha (dual-link)
A device can use this attribute internally to handle data conversions or routing. For example, the OCTANE Digital Video board includes an alpha LUT to convert CCIR-range pixel data to full-range alpha values.
direction: source or drain
enumerator: A, B, C, and so on, used if a path has several ports with the same link type, data type, and direction
Ports produce or consume various types of data: pixel, alpha, or dual-link data. The identification of the port as pixel or alpha may cause the video stream to be treated differently. For example, alpha data, which can be supplied to OCTANE video in the CCIR range only, is internally expanded to full range before it is used. No range expansion is performed for pixel data. Dual-link channels carry both alpha and pixel data, although one data type may be ignored depending on the format.
Ports have generic names; for example:
VL_IMPACT_PORT_PIXEL_SRC_A: source of a pixel stream (first, or only, port instance)
VL_IMPACT_PORT_ALPHA_DRN_B: drain of an alpha stream (second port instance)
For the symbolic names for ports, see /usr/include/dmedia/dev_impact.h. Appendix A, “Video Library Controls and Compression Library Parameters for the OCTANE Compression Option,” gives the ports associated with each node.
The connections between ports on nodes determine the topology of a path. Single-link ports can be connected to single-link ports only; dual-link ports can be connected to double-link ports only.
Data flows from a source port to a drain port. It is not permissible to connect a source port to another source port, or a drain port to another drain port.
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:
vlSetConnection() sets a connection between a source pair (node, port) pair and a drain pair (node, port).
vlGetConnection() returns the set of connections entering or leaving a node or port.
The OCTANE Compression board translates video signals into a form usable by the Indigo2 workstation. It also does the reverse, translating memory buffers into video signals.
Table 3-1 summarizes the formats that the OCTANE Compression board supports.
Table 3-1. Video Formats for OCTANE Compression
Format | Signal | Nodes |
---|---|---|
SMPTE YUV (VL_FORMAT_SMPTE_YUV) | Contains YUV components in the range 1-254; superblack and superwhite values can be present. | All memory nodes |
RGB (VL_FORMAT_RGB) | Full-range 8-bit per component RGBA. Component range is 0 to 255 (8-bit). |
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 that do not involve memory (video in to video out), which do not require setting up 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:
Open a connection to the video daemon (vlOpenVideo()); if necessary, determine which device the application will use (vlGetDevice(), vlGetDeviceList()).
Specify nodes on the data path (vlGetNode()).
Create the path (vlCreatePath()).
(Optional step) Add more connections to a path (vlAddNode()).
Set up the hardware for the path (vlSetupPaths()).
Specify path-related events to be captured (vlSelectEvents()).
Set input and output parameters (controls) for the nodes on the path (vlSetControl()).
For transfers involving memory, create a VL buffer to hold data for memory transfers (vlGetTransferSize(), dmBufferCreatePool() or vlCreateBuffer()).
For transfers involving memory, register the buffer (vlRegisterBuffer()) or (video-to-memory only) vlDMBufferPoolRegister()
Set the path topology (vlSetConnection()).
Start the data transfer (vlBeginTransfer()).
For transfers involving memory, get the data and manipulate it (DMbuffers: vlDMBufferGetValid(), vlGetActiveRegion(), dmBufferFree(); VL buffers: vlGetNextValid(), vlGetLatestValid(), vlGetActiveRegion(), vlPutFree()).
Clean up (vlEndTransfer(), vlDeregisterBuffer(), vlDestroyPath(), dmBuffer() or vlDestroyBuffer(), vlCloseVideo()).
Table 3-2 lists calls explained in this chapter.
Table 3-2. Video Library Calls for Data Transfer
All Transfers | Transfers Involving Memory | Setting Controls |
---|---|---|
vlOpenVideo() | vlGetTransferSize() | vlSetControl() |
To build programs that run under VL, you must
install the dmedia_dev option
link with libvl.so
include vl.h, dev_mgv.h, and dev_mgc.h
The client library is /usr/lib/libvl.so. The header files for the VL are in /usr/include/dmedia; see “Library and Header Files” for a list.
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("") |
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:
| |||
kind | specifies the kind of node: | |||
number | is the number of the node in cases of two or more identical nodes, such as two 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.
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
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. |
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); |
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 source node and a blend node:
vlAddNode(vlSvr, vlPath, src_vid); vlAddNode(vlSvr, vlPath, blend_node); |
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
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); } |
![]() | Note: The Video Library infers the connections on a path if vlBeginTransfer() is called and no drain nodes have been connected using vlSetConnection() (implicit routing). To specify a path that does not use the default connections, use vlSetConnection() (explicit routing). |
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.
![]() | Note: Do not combine implicit and explicit routing. |
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 3-3 lists the possibilities |
Table 3-3 lists and describes the 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); |
Transferring data to or from memory requires creating a VL buffer; its size is determined by the size of the frame data you are transferring.
To set frame data size and to convert from one video format to another, apply controls to the nodes. The use of source node controls and drain node controls is explained separately in this section.
Important data transfer controls for source and drain nodes are summarized in Table 3-4. They should be set in the order in which they appear in the table.
These controls are highly interdependent, so the order in which they are set is important. In most cases, the value being set takes precedence over other values that were previously set.
![]() | Note: For drain nodes, VL_PACKING must be set first. Note that changes in one parameter may change the values of other parameters set earlier; for example, clipped size may change if VL_PACKING is set after VL_SIZE. |
Table 3-4. Data Transfer Controls
Control | Basic Use | Video Nodes | Memory and Codec Nodes |
---|---|---|---|
VL_FORMAT | Video format on the physical connector | See “Using VL_FORMAT” in this chapter | N/A |
VL_TIMING | Video timing | See Table 3-5 for values | N/A |
VL_CAP_TYPE | Setting type of field(s) or frame(s) to capture | N/A | VL_CAPTURE_NONINTERLEAVED |
VL_PACKING | Pixel packing (conversion) format | N/A | Changes pixel format of captured data; see Table 3-7 for values |
VL_ZOOM | Decimation size | N/A | Memory nodes only: any n/m where n
is less than or equal to m |
VL_SIZE | Clipping size | Full size of video; read only | Clipped size |
VL_OFFSET | Position within larger area | Position of active region; read only | Offset relative to video offset |
VL_RATE | Field or frame transfer speed | N/A | If type is INTERLEAVED, rate is in frames; otherwise, it is in fields |
To determine default values, use vlGetControl() to query the values on the video source or drain node before setting controls. The initial offset of the video node is the first active line of video.
Similarly, the initial size value on the video source or drain node is the full size of active video being captured by the hardware, beginning at the default offset. Because some hardware can capture more than the size given by the video node, this value should be treated as a default size.
For all these controls, it pays to track return codes. If the value returned is VLValueOutOfRange, the value set is not what you requested.
To specify the controls, use vlSetControl(), for which the function prototype is
int vlSetControl(VLServer vlSvr, VLPath vlPath, VLNode node, VLControlType type, VLControlValue * value) |
The use of VL_TIMING, VL_FORMAT, VL_PACKING, VL_ZOOM, VL_SIZE, VL_OFFSET, VL_CAP_TYPE, and VL_RATE is explained in more detail in the following sections.
Timing type expresses the timing of video presented to a source or drain. Table 3-5 summarizes dimensions for VL_TIMING.
Table 3-5. Dimensions for Timing Choices
| Maximum Width | Maximum Height |
---|---|---|
VL_TIMING_525_SQ_PIX (12.27 MHz) | 640 | 486 |
VL_TIMING_625_SQ_PIX (14.75 MHz) | 768 | 576 |
VL_TIMING_525_CCIR601 (13.50 MHz) | 720 | 486 |
VL_TIMING_625_CCIR601 (13.50 MHz) | 720 | 576 |
To specify video input and output formats of the video signal on the physical connector, use VL_FORMAT. Table 3-6 summarizes the options.
Format | Explanation |
---|---|
VL_FORMAT_SMPTE_YUV | 8-bit YCrCb |
VL_FORMAT_RGB | Full-range 8-bit (0-255) RGBA |
A video packing describes how a video signal is stored in memory, in contrast to a video format, which describes the characteristics of the video signal.
Packings are specified through the VL_PACKING control on the memory nodes. This control also converts one video output format to another in memory, within the limits of the nodes.
Packing types for eight bits per component are summarized in Table 3-7.
Table 3-7. Packing Types for Eight Bits per Component
Type | 63-56 | 55-48 | 47-40 | 39-32 | 31-24 | 23-16 | 15-8 | 7-0 |
---|---|---|---|---|---|---|---|---|
VL_PACKING_YVYU_422_8 | U0 | Y0 | V0 | Y1 | U2 | Y2 | V2 | Y3 |
VL_PACKING_RGB_8 | X0 | B0 | G0 | R0 | X1 | B1 | G1 | R1 |
In the VL, VL_ZOOM controls the expansion or decimation of the video image. For OCTANE Compression, VL_ZOOM is used in this way:
OCTANE Compression memory drain nodes support any ratio where the numerator is less than or equal to the denominator—that is, decimation, but not zoom.
Other OCTANE Compression nodes support zoom and decimation ratios of 1:1 only, that is, neither zoom nor decimation.
Figure 3-4 illustrates decimation.
VL_ZOOM takes a nonzero fraction as its argument; do not use negative values. For example, this fragment captures half-size decimation video to the screen:
val.fractVal.numerator = 1; val.fractVal.denominator = 2; if (vlSetControl(server, screen_path, screen_drain_node, VL_ZOOM, &val)){ vlPerror("Unable to set zoom"); exit(1); } |
![]() | Note: For a source, decimation takes place before blending; for a drain, blending takes place before decimation. |
This fragment captures half-size decimation video to the screen, with clipping to 320 × 243 (NTSC size minus overscan):
val.fractVal.numerator = 1; val.fractVal.denominator = 2; if (vlSetControl(server,screen_path, screen_drain_node, VL_ZOOM, &val)) { vlPerror("Unable to set zoom"); exit(1); } val.xyVal.x = 320; val.xyVal.y = 243; if (vlSetControl(server, screen_path, screen_drain_node, VL_SIZE, &val)) { vlPerror("Unable to set size"); exit(1); } |
This fragment captures xsize × ysize video with as much decimation as possible, assuming the size is smaller than the video stream:
if (vlGetControl(server, screen_path, screen_source, VL_SIZE, &val)) { vlPerror("Unable to get size"); exit(1); } if (val.xyVal.x/xsize < val.xyVal.y/ysize) zoom_denom = (val.xyVal.x + xsize - 1)/xsize; else zoom_denom = (val.xyVal.y + ysize - 1)/ysize; val.fractVal.numerator = 1; val.fractVal.denominator = zoom_denom; if (vlSetControl(server, screen_path, screen_drain_node, VL_ZOOM, &val)) { /* allow this error to fall through */ vlPerror("Unable to set zoom"); } val.xyVal.x = xsize; val.xyVal.y = ysize; if (vlSetControl(server, screen_path, screen_drain_node, VL_SIZE, &val)) { vlPerror("Unable to set size"); exit(1); } |
VL_SIZE controls how much of the image sent to the drain is used, that is, how much clipping takes place. This control operates on the zoomed image; for example, when the image is zoomed to half size, the limits on the size control change by a factor of 2. Figure 3-5 illustrates clipping.
For example, to display PAL video in a 320 × 243 space, clip the image to that size, as shown in the following fragment:
VLControlValue value; |
value.xyval.x=320; value.xyval.y=243; vlSetControl(vlSvr, path, drn, VL_SIZE, &value); |
![]() | Note: Because this control is device-dependent and interacts with other controls, always check the error returns. For example, if offset is set before size and an error is returned, set size before offset. |
VL_OFFSET puts the upper left corner of the video data at a specific position; it sets the beginning position for the clipping performed by VL_SIZE. The values you enter are relative to the origin.
This example places the data ten pixels down and ten pixels in from the left:
VLControlValue value; |
value.xyval.x=10; value.xyval.y=10; vlSetControl(vlSvr, path, drn, VL_OFFSET, &value); |
To capture the blanking region, set offset to a negative value.
Figure 3-6 shows the relationships between the source and drain size, and offset.
![]() | Note: For memory nodes, VL_OFFSET and VL_SIZE in combination define the active region of video that is transferred to or from memory. |
An application can request that OCTANE Compression capture or play back a video stream in a number of ways. For example, the application can request that each field be placed in its own buffer, that each buffer contain an interleaved frame, or that only odd or even fields be captured. This section enumerates the capture types that OCTANE Compression supports.
A field mask is useful for identifying which fields will be captured and played back and which fields will be dropped. A field mask is a bit mask of 60 bits for NTSC or 50 bits for PAL (two fields per frame). A numeral 1 in the mask indicates that a field is captured or played back, while a zero indicates that no action occurs.
For example, the following field mask indicates that every other field will be captured or played back:
10101010101010101010... |
Capture types are as follows:
VL_CAPTURE_NONINTERLEAVED
VL_CAPTURE_INTERLEAVED
VL_CAPTURE_EVEN_FIELDS
VL_CAPTURE_ODD_FIELDS
VL_CAPTURE_FIELDS
VL_RATE determines the data transfer rate by field or frame, depending on the capture type as specified by VL_CAP_TYPE, as shown in Table 3-8.
Table 3-8. VL_RATE Values (Items per Second)
VL_CAP_TYPE Value | VL_RATE Value |
---|---|
VL_CAPTURE_NONINTERLEAVED, VL_CAPTURE_INTERLEAVED | NTSC: 1-30 frames/second |
VL_CAPTURE_EVEN_FIELDS, | NTSC: 1-30 fields/second |
VL_CAPTURE_FIELDS | NTSC: 1-60 fields/second |
![]() | Note: Not all rates are supported on all memory nodes; see Appendix A, “VL Controls and CL Parameters for the OCTANE Compression Option,” for details. The buffer size must be set in accordance with the capture type, as listed in Table 3-10 in this chapter. |
The VL_CAPTURE_NONINTERLEAVED capture type specifies that frame-size units are captured noninterleaved. Each field is placed in its own buffer, with the dominant field in the first buffer. If one of the fields of a frame is dropped, all fields are dropped. Consequently, an application is guaranteed that the field order is maintained; no special synchronization is necessary to ensure that fields from different frames are mixed.
The rate (VL_RATE) for noninterleaved capture is in terms of fields and must be even. For NTSC, the capture rate may be from 2 to 60 fields per second, and for PAL, from 2 to 50 fields per second. Because a frame is always captured as a whole, a rate of 30 fields per second results in the following field mask:
1100110011001100... |
The first bit in the field mask corresponds to the dominant field of a frame. OCTANE Digital Video waits for a dominant field before it starts the transfer.
If VL_CAPTURE_NONINTERLEAVED is specified for playback, similar guarantees apply as for capture. If one field is lost during playback, it is not possible to “take back” the field. OCTANE Digital Video resynchronizes on the next frame boundary, although black or “garbage” video might be present between the erring field and the frame boundary.
The rate during playback also follows the rules for capture. For each 1 in the mask above, a field from the VL buffer is output. During the 0 fields, the previous frame is repeated. Note that the previous frame is output, not just the last field. If there are a pair of buffers, the dominant field is placed in the first buffer.
Interleaved capture interleaves the two fields of a frame and places them in a single buffer; the order of the frames depends on the value set for VL_MGV_DOMINANCE_FIELD (see Table A-3 or Table A-4 in Appendix A for details). OCTANE Digital Video guarantees that the interleaved fields are from the same frame: if one field of a frame is dropped, then both are dropped.
The rate for interleaved frames is in frames per second: 1-30 frames per second for NTSC and 1-25 frames per second for PAL. A rate of 15 frames per second results in every other frame being captured. Expressed as a field mask, the following sequence is captured:
1100110011001100.... |
As with VL_CAPTURE_NONINTERLEAVED, OCTANE Digital Video begins processing the field mask when a dominant field is encountered.
During playback, a frame is deinterleaved and output as two consecutive fields, with the dominant field output first. If one of the fields is lost, OCTANE Digital Video resynchronizes to a frame boundary before playing the next frame. During the resynchronization period, black or “garbage” data may be displayed.
Rate control follows similar rules as for capture. For each 1 in the mask above, a field from the interleaved frame is output. During 0 periods, the previous frame is repeated.
In the VL_CAPTURE_EVEN_FIELDS capture type, only even (F2) fields are captured, with each field placed in its own buffer. Expressed as a field mask, the captured fields are
1010101010101010... |
OCTANE Digital Video begins processing this field mask when an even field is encountered.
The rate for this capture type is expressed in even fields. For NTSC, the range is 1-30 fields per second, and for PAL 1-25 fields per second. A rate of 15 fields per second (NTSC) indicates that every other even field is captured, yielding a field mask of
1000100010001000... |
During playback, the even field is repeated as both the F1 and F2 fields, until it is time to output the next buffer. If a field is lost during playback, black or “garbage” data might be displayed until the next buffer is scheduled to be displayed.
The VL_CAPTURE_ODD_FIELDS capture type works the same way as VL_CAPTURE_EVEN_FIELDS, except that only odd (F1) fields are captured, with each field placed in its own buffer. The rate for this capture type is expressed in odd fields. A rate of 15 fields per second (NTSC) indicates that every other odd field is captured. Field masks are the same as for VL_CAPTURE_EVEN_FIELDS.
The VL_CAPTURE_FIELDS capture type captures both even and odd fields and places each in its own buffer. Unlike VL_CAPTURE_NONINTERLEAVED, there is no guarantee that fields are dropped in frame units. Field synchronization can be performed by examining the UST, the MSC, or the dmedia info sequence number associated with each field.
The rate for this capture type is expressed in fields. For NTSC, the range is
1-60 fields per second, and for PAL 1-50 fields per second. A rate of 30 fields per second (NTSC) indicates that every other field is captured, resulting in the following field mask:
101010101010101010... |
Contrast this with the rate of 30 for VL_CAPTURE_NONINTERLEAVED, which captures every other frame.
Field mask processing begins on the first field after the transfer is started; field dominance, evenness, oddness play no role in this capture type.
![]() | Note: The OCTANE Digital Video can make use of the Unadjusted System Time (UST)/Media Stream Count (MSC) feature. See Chapter 2 of the OCTANE Digital Video Programmer's Guide for information. |
Use the control VL_MGC_DOMINANCE_FIELD to set the field dominance mode, which determines the order in which the fields are read from memory. This control applies only to the frame-oriented capture types VL_CAPTURE_INTERLEAVED and VL_CAPTURE_NONINTERLEAVED.
The values for the control VL_MGC_DOMINANCE_FIELD are VL_MGC_DOMINANCE_F1 (the default) and VL_MGC_DOMINANCE_F2. Figure 3-7 diagrams the field dominance values.
You can set field dominance independently for each DMA channel.
VL_CAPTURE_INTERLEAVED
VL_MGC_DOMINANCE_F1: For video timings VL_TIMING_525_CCIR601 and VL_TIMING_525_SQ_PIX, F1 (odd) dominance dictates that data for the F1 field resides in memory after that for F2. For VL_TIMING_625_CCIR601 and VL_TIMING_625_SQ_PIX, the data for F1 resides in memory before that of F2.
VL_MGC_DOMINANCE_F2: For VL_TIMING_525_CCIR601 and VL_TIMING_525_SQ_PIX, F2 (even timings) dominance dictates that data for the F1 field resides in memory before that for F2. For VL_TIMING_625_CCIR601 and VL_TIMING_625_SQ_PIX, the data for F1 resides in memory after that of F2.
The meaning of before and after depends on the capture type. For interleaved frames, before indicates that the data comprising the first line of the designated field begins at the first byte of the buffer. In this format, the lines of F1 and F2 are interleaved within the one ring buffer, thus the second line of the buffer belongs to the other field, and so forth.
For noninterleaved frames, before indicates that the dominant field is in a buffer preceding the buffer(s) containing nondominant fields.
Values for VL_CAPTURE_NONINTERLEAVED:
VL_MGC_DOMINANCE_F1: The F1 field is in the first buffer of the pair, and the F2 field in the second.
VL_MGC_DOMINANCE_F2: The F2 field is in the first buffer of the pair, the F1 field in the second.
OCTANE Compression has hardware acceleration for shrinking images that have an original size of up to 1000 × 1000 pixels. Original sizes with height or width larger than 1000 pixels are sized (and optionally converted to the RGB color space) by software on the host CPU.
Table 3-9 lists controls you can use to pad and scale images on capture.
Table 3-9. Padding and Scaling Controls
Control | Values or Range | Type | Use |
---|---|---|---|
0 < value ≤ 1/VL_ZOOM | fractVal | Fraction less than or equal to 1 that shrinks the horizontal or vertical aspect, respectively | |
\xb3 0 | intVal | Number of lines to pad at the top or bottom (respectively of the image on capture | |
\xb3 0 | intVal | Number of pixels to pad at the left or right (respectively) of the image on capture | |
0, 1 | boolVal | Boolean value that activates or deactivates padding | |
1 ≤ value ≤ 254 | intVal | Value between 16 and 235 that specifies the padding color of the Y, U, or V value, respectively; default is black | |
\xb3 0 | intVal | Number of lines to clip from the top on playback to video output |
For examples, see /usr/share/src/dmedia/video/vl/OpenGL/contcapt.c.
The processes for data transfer are as follows:
creating a buffer for video data (for transfers involving memory)
registering the VL buffer with the path (for transfers involving memory)
starting data transfer
reading data from the buffer (for transfers involving memory)
Each process is explained separately.
![]() | Note: You can use either VL buffers or DM buffers. For information on DMbuffers, see Chapter 5 of the Digital Media Programming Guide (007-1799-060), or Chapter 2 of the OCTANE DIgital Video Programmer's Guide (007-3513-001). |
Once you have specified frame parameters in a transfer involving memory (or have determined to use the defaults), create a buffer for the video data. In this case, video data is frames or fields, depending on the capture type:
frames if the capture type is VL_CAPTURE_NONINTERLEAVED
fields if the capture type is anything else
Like other libraries in the IRIX digital media development environment, the VL uses VL buffers. VL buffers provide a way to read and write varying sizes of video data. A frame of data consists of the actual frame data and an information structure describing the underlying data, including device-specific information.
When a VL buffer is created, constraints are specified that control the total size of the data segment and the number of frame or field buffers (sectors) to allocate.
A head and a tail flag are automatically set in a VL buffer so that the latest frame can be accessed. A sector is locked down if it is not called; that is, it remains locked until it is read. When the VL buffer is written to and all sectors are occupied, data transfer stops. The sector last written to remains locked down until it is released.
All sectors in a VL buffer must be of the same size, which is the value returned by vlGetTransferSize(). Its function prototype is
long vlGetTransferSize(VLServer vlSvr, VLPath path) |
For example:
transfersize = vlGetTransferSize(vlSvr, path); |
where transfersize is the size of the data in bytes.
To create a VL buffer for the frame data, use vlCreateBuffer(). Its function prototype is
VLBuffer vlCreateBuffer(VLServer vlSvr, VLPath path, VLNode node, int numFrames) |
where
VLBuffer | is the handle of the buffer to be created | |
vlSvr | names the server to which the path is connected | |
path | specifies the data path | |
node | specifies the memory node containing data to transfer to or from the VL buffer | |
numFrames | specifies the number of sectors in the buffer (fields or frames, depending on the capture type) |
For example:
buf = vlCreateBuffer(vlSvr, path, src, 1); |
Table 3-10 shows the relationship between capture type and minimum VL buffer size.
Table 3-10. Buffer Size Requirements
Capture Type | Minimum Sectors for Capture | Minimum Sectors for Playback |
---|---|---|
VL_CAPTURE_NONINTERLEAVED | 2 | 4 |
VL_CAPTURE_INTERLEAVED | 1 | 2 |
VL_CAPTURE_EVEN_FIELDS | 1 | 2 |
VL_CAPTURE_ODD_FIELDS | 1 | 2 |
VL_CAPTURE_FIELDS | 1 | 2 |
![]() | Note: For memory nodes, real-time memory or video transfer can be performed only as long as buffer sectors are available to the OCTANE Digital Video device. |
Use vlRegisterBuffer() to register the VL buffer with the data path. Its function prototype is
int vlRegisterBuffer(VLServer vlSvr, VLPath path, VLNode memnodeid, VLBuffer buffer) |
where
vlSvr | names the server to which the path is connected | |
path | specifies the data path | |
memnodeid | specifies the memory node ID | |
buffer | specifies the VL buffer handle |
For example:
vlRegisterBuffer(vlSvr, path, drn, Buffer); |
To begin data transfer, use vlBeginTransfer(). Its function prototype is
int vlBeginTransfer(VLServer vlSvr, VLPath path, int count, VLTransferDescriptor* xferDesc) |
where
vlSvr | names the server to which the path is connected | |
path | specifies the data path | |
count | specifies the number of transfer descriptors | |
xferDesc | specifies an array of transfer descriptors |
Tailor the data transfer by means of transfer descriptors. Multiple transfer descriptors are supplied; they are executed in order. The transfer descriptors are
xferDesc.mode | Transfer method:
| |
xferDesc.count | Number of frames to transfer; if mode is VL_TRANSFER_MODE_CONTINUOUS, this value is ignored. | |
xferDesc.delay | Number of frames from the trigger at which data transfer begins. | |
xferDesc.trigger | Set of events to trigger on; an event mask. This transfer descriptor is always required. VLTriggerImmediate specifies that transfer begins immediately, with no pause for a trigger event. VLDeviceEvent specifies an external trigger. If xferDesc is NULL, then VL_TRIGGER_IMMEDIATE and VL_TRANSFER_CONTINOUS_MODE are assumed and one transfer is performed. |
This example fragment transfers the entire contents of the buffer immediately.
xferDesc.mode = VL_TRANSFER_MODE_DISCRETE; |
xferDesc.count = imageCount; xferDesc.delay = 0; xferDesc.trigger = VLTriggerImmediate; |
This fragment shows the default descriptor, which is the same as passing in a null for the descriptor pointer. Transfer begins immediately; count is ignored.
xferDesc.mode = VL_TRANSFER_MODE_CONTINUOUS; |
xferDesc.count = 0; xferDesc.delay = 0; xferDesc.trigger = VLTriggerImmediate; |
If your application uses a buffer, use various VL calls for reading frames, getting pointers to active buffers, freeing buffers, and other operations. Table 3-11 lists the buffer-related calls
Table 3-11. Buffer-Related Calls
Call | Purpose |
---|---|
vlGetNextValid() | Returns a handle on the next valid frame or field of data |
vlGetLatestValid() | Reads only the most current frame or field in the buffer, discarding the rest |
vlPutValid() | Puts a frame or field into the valid list (memory to video) |
vlPutFree() | Puts a valid frame or field back into the free list (video to memory) |
vlGetNextFree() | Gets a free buffer into which to write data (memory to video) |
vlBufferDone() | Informs you if the buffer has been vacated |
vlBufferReset() | Resets the buffer so that it can be used again |
Figure 3-8 illustrates the difference between vlGetNextValid() and vlGetLatestValid(), and their interaction with vlPutFree().
Table 3-12 lists the calls that extract information from a buffer.
Table 3-12. Calls for Extracting Data From a Buffer
Call | Purpose |
---|---|
vlGetActiveRegion() | Gets a pointer to the data region of the buffer (video to memory); called after vlGetNextValid() and vlGetLatestValid() |
vlGetDMediaInfo() | Gets a pointer to the DMediaInfo structure associated with a frame; this structure contains timestamp and field count information |
vlGetImageInfo() | Gets a pointer to the DMImageInfo structure associated with a frame; this structure contains image size information |
![]() | Caution: None of these calls has count or block arguments; appropriate calls in the application must deal with a NULL return in cases of no data being returned. |
In summary, for video-to-memory transfer, use
buffer = vlCreateBuffer(vlSvr, path, memnode1); vlRegisterBuffer(vlSvr, path, memnode1, buffer); vlBeginTransfer(vlSvr, path, 0, NULL); info = vlGetNextValid(vlSvr, buffer); /* OR vlGetLatestValid(vlSvr, buffer); */ dataptr = vlGetActiveRegion(vlSvr, buffer, info); /* use data for application */ … vlPutFree(vlSvr, buffer); |
For memory-to-video transfer, use
buffer = vlCreateBuffer(vlSvr, path, memnode1); vlRegisterBuffer(vlSvr, path, memnode1, buffer); vlBeginTransfer(vlSvr, path, 0, NULL); buffer = vlGetNextFree(vlSvr, buffer, bufsize); /* fill buffer with data */ … vlPutValid(vlSvr, buffer); |
These calls are explained in separate sections.
Use vlGetNextValid() to read all the frames in the buffer or get a valid frame of data. Its function prototype is
VLInfoPtr vlGetNextValid(VLServer vlSvr, VLBuffer vlBuffer) |
Use vlGetLatestValid() to read only the most current frame in the buffer, discarding the rest. Its function prototype is
VLInfoPtr vlGetLatestValid(VLServer vlSvr, VLBuffer vlBuffer) |
After removing interesting data, return the buffer for use with vlPutFree() (video to memory). Its function prototype is
int vlPutFree(VLServer vlSvr, VLBuffer vlBuffer) |
Use vlGetNextFree() to get a free buffer to which to write data. Its function prototype is
VLInfoPtr vlGetNextFree(VLServer vlSvr, VLBuffer vlBuffer, int size) |
After filling the buffer with the data you want to send to video output, use vlPutValid() to put a frame into the valid list for output to video (memory to video). Its function prototype is
int vlPutValid(VLServer vlSvr, VLBuffer vlBuffer) |
![]() | Caution: These calls do not have count or block arguments; appropriate calls in the application must deal with a NULL return in cases of no data being returned. |
Use vlGetActiveRegion() to get a pointer to the active buffer. Its function prototype is
void * vlGetActiveRegion(VLServer vlSvr, VLBuffer vlBuffer, VLInfoPtr ptr) |
Use vlGetDMediaInfo() to get a pointer to the DMediaInfo structure associated with a frame. This structure contains timestamp and field count information. The function prototype for this call is
DMediaInfo * vlGetDMediaInfo(VLServer vlSvr, VLBuffer vlBuffer, VLInfoPtr ptr) |
Use vlGetImageInfo() to get a pointer to the DMImageInfo structure associated with a frame. This structure contains image size information. The function prototype for this call is
DMImageInfo * vlGetImageInfo(VLServer vlSvr, VLBuffer vlBuffer, VLInfoPtr ptr) |
To end data transfer, use vlEndTransfer(). Its function prototype is
int vlEndTransfer(VLServer vlSvr, VLPath path) |
A discrete transfer is finished when the last frame of the sequence is output. The two types of memory nodes behave differently at the last frame:
The CC1 memory source stops transferring data from main memory to the OCTANE Digital Video device, but continues to output to video the last frame transferred, which is held in a frame buffer associated with the CC1 memory node.
The VGI1 memory nodes have no associated frame buffer and consequently emit black video output after a transfer (discrete or continuous) has been completed.
To accomplish the necessary cleanup to exit gracefully, use the following functions:
The function prototype for vlDeregisterBuffer() is
int vlDeregisterBuffer(VLServer vlSvr, VLPath path, VLNode memnodeid, VLBuffer ringbufhandle) |
where
vlSvr | is the server handle | |
path | is the path handle | |
memnodeid | is the memory node ID | |
ringbufhandle | is the VL buffer handle |
The function prototypes for vlDestroyPath(), vlDestroyBuffer() and vlCloseVideo() are, respectively,
int vlDestroyPath(VLServer vlSvr, VLPath path) int vlDestroyBuffer(VLServer vlSvr, VLBuffer vlBuffer) int vlCloseVideo(VLServer vlSvr) |
This example ends a data transfer that used a buffer:
vlEndTransfer(vlSvr, path); vlDeregisterBuffer(vlSvr, path, memnodeid, buffer); vlDestroyPath(vlSvr, path); vlDestroyBuffer(vlSvr, buffer); vlCloseVideo(vlSvr); |
The directory /usr/share/src/dmedia/video/vl includes a number of example programs. These programs illustrate how to create simple video applications; for example:
a simple screen application: simplev2s.c
This program shows how to send live video to the screen.
a video-to-memory frame grab: simplegrab.c
This program demonstrates video frame grabbing.
memory-to-video frame output simplem2v.c
This program sends a frame to the video output.
continuous frame capture: simpleccapt.c
This program demonstrates continuous frame capture.
![]() | Note: To simplify the code, these examples do not check returns. However, you should always check returns. |
The directory /usr/share/src/dmedia/video/vl/OpenGL contains three example OpenGL programs:
These programs are the OpenGL equivalents of the programs with the same names in /usr/share/src/dmedia/video/vl.