The Video Library (VL) is a collection of device-independent C language calls for Silicon Graphics® workstations equipped with video options, such as Sirius Video™, Indigo2 Video™, Indy Video™, or Galileo Video ™, or workstations equipped with on-board video (VINO™: video in, no out), such as Indy™. The VL includes generic video tools, including simple tools for importing and exporting digital data to and from current and future Silicon Graphics products, as well as to and from third-party video devices that adhere to the Silicon Graphics architectural model for video devices.
VL calls enable you to perform video teleconferencing on platforms that support it, to blend computer-generated graphics with frames from videotape or any video source, and to present video in a window on the workstation screen and to digitize video data.
![]() | Note: The range of VL capabilities you can use depends on the capabilities of your workstation and the video options installed in it. |
Topics in this chapter include:
The chapter concludes with example code illustrating a simple screen application and frame grabs (video to memory, memory to video, and continuous frame capture).
The VL includes calls for querying features of all supported Silicon Graphics video options. The VL supports conversion from one video format to another (for example, YUV to RGB or RGB to YUV).
In some cases, the VL can support multiple devices of the same or of different types. For example, the CHALLENGE™ architecture supports multiple Sirius Video boards; Indy supports its built-in video (VINO) and the Indy Video option.
The Video Library works with other Silicon Graphics libraries, such as the OpenGL, the IRIS GL and the IRIS ImageVision Library (IL). Software supplied with optional video hardware provides additional video capabilities through extensions to the VL. For example, Sirius Video software includes controls specific to that hardware.
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. Frame rate depends on the capabilities of the hardware you are using.
![]() | Note: 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. |
This section describes features of these VL system components and tools:
video daemon
generic video tools
library and header files
Figure 12-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).
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 device management
Some hardware devices support multiple video products in one system. The video daemon is responsible for establishing and coordinating the availability of all video devices installed.
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 man pages, these tools have explanations 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 4Dgifts directory (/usr/people/4Dgifts/examples/dmedia/video/vl).
![]() | Note: Additional video tools may be available for specific on-board video or video options; see the documentation for those products. |
The client library is /usr/lib/libvl.a. The header files for the VL are in /usr/include/dmedia/vl; the main file is vl.h. This file contains the main definition of the VL API and controls that are common across all hardware.
Device-dependent files use the form vl_XXX.h, where XXX is replaced with the device-dependent name. Table 12-1 lists header files for hardware options that use the VL. These files contain additional controls specific to the devices.
Table 12-1. Header Files for Video Options
Hardware | Header File |
|---|---|
Galileo Video, Indigo2 Video, Indy Video | vl_ev1.h |
Sirius Video | vl_sirius.h |
Video capability built into Indy workstation | vl_vino.h |
The two central concepts for VL are:
VL routines explained in this chapter enable you to build a fully connected topology of sources and drains.
A path defines the useful connections between video sources and video drains. Figure 12-2 shows a simple path in which a frame from a videotape is displayed in a workstation window.
Some Silicon Graphics platforms are capable of supporting more than one video device; for example, Indy supports VINO and Indy Video. Each video device has its own data paths with sources and drains. The application is responsible for looking at the capabilities of the platform and choosing the video device it will run on.
Figure 12-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 VL recognizes five classes of objects:
devices, each including sets of nodes
nodes: sources, drains, and internal nodes
paths, connecting sources and drains
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 and receiving frame data to and from host memory; the VL buffers are implemented as ring buffers containing a number of blocks; each maintains a pointer, a size, and pointers to the head (oldest) and tail (newest) valid data
Data transfers fall into two categories:
transfers involving memory (video to memory, memory to video), which require setting up a ring buffer
transfers not involving memory (such as video to screen and graphics to video), which do not require a ring buffer (such transfers are not supported on VINO)
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()
For the two categories of data transfer, based on the VL programming model, the process of creating a VL application consists of these steps:
opening a connection to the video daemon (vlOpenVideo()); if necessary, determining which device the application will use (vlGetDevice(), vlGetDeviceList())
specifying nodes on the data path (vlGetNode())
creating the path (vlCreatePath())
optional step: adding more connections to a path (vlAddNode())
setting up the hardware for the path (vlSetupPaths())
specifying path-related events to be captured (vlSelectEvents())
setting input and output parameters (controls) for the nodes on the path (vlSetControl())
transfers involving memory: creating a ring buffer to hold data for memory transfers (vlGetTransferSize(), vlCreateBuffer())
transfers involving memory: registering the buffer (vlRegisterBuffer())
starting the data transfer (vlBeginTransfer())
transfers involving memory: getting the data (vlGetNextValid() or vlGetLatestValid(), vlGetActiveRegion(), vlPutFree()) to manipulate frame data
cleanup (vlEndTransfer(), vlDeregisterBuffer(), vlDestroyPath(), vlDestroyBuffer(), vlCloseVideo())
Table 12-2 lists calls explained in this chapter.
Table 12-2. Video Library Calls for Data Transfer
All Transfers | Transfers Involving Memory | Setting Controls |
|---|---|---|
vlOpenVideo() | vlGetTransferSize() | vlSetControl() |
Preliminary procedures required to create the data path are:
opening the device
specifying nodes on the data path
creating and setting up the data path
Each procedure is explained separately.
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:
svr = vlOpenVideo("")
|
Use vlGetNode() to specify nodes; this call returns the node's handle. Its function prototype is:
VLNode vlGetNode(VLServer vlServer, int type, int kind, int number) |
where:
| VLNode | is a handle for the node, used when setting controls or setting up paths | |||
| vlServer | 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 use the default node kind, use VL_ANY.
nodehandle = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY); |
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(svr, path, VL_ANY, VL_DEFAULT_SOURCE, &ctrlval); nodehandle = vlGetNode(svr, VL_SRC, VL_VIDEO, ctrlval.intVal); |
In the second line above, the last argument is a struct that gets the value.
![]() | Note: If either VINO analog channel is active when the first video application starts, the default is analog; otherwise, the default is digital. |
Once nodes are specified, use VL calls to:
determine the device ID (optional step)
create the path
get the device ID
add nodes (optional step)
set up the data path
specify the path-related events to be captured
In this optional step, use one of the following calls to determine the device on which the data path will be created, depending on the situation.
If you do not know which device of several available is appropriate for the data path, get the device list with vlGetDeviceList(). Its function prototype is:
int vlGetDeviceList(VLServer vlServer, VLDevList * devlist) |
If you know the device you want, parse devlist to get its handle. Otherwise, the VL selects the first device that the path you have specified can run on.
Use this step for systems with multiple devices of different capabilities; for example, on an Indy workstation with VINO and Indy Video, for full frame rate capture, specify VINO, though both devices support the video input path.
The struct for nodeinfo in vl.h is:
typedef struct __vlNodeInfo {
char name[VL_NAME_SIZE]; /* name of node */
int type; /* see list above */
int number; /* number of this node */
int kind; /* see list above */
} VLNodeInfo;
|
The struct for dev in vl.h is:
typedef struct __vlDevice {
VLDev dev;
char name[VL_NAME_SIZE]; /* name of device */
uint numNodes; /* number of nodes on this device */
VLNodeInfo *nodes; /* list of nodes */
} VLDevice;
|
The struct for devlist in vl.h is:
typedef struct __vlDevList {
uint numDevices; /* number of devices */
VLDevice *devices; /* list of devices */
} VLDevList;
|
Use vlCreatePath() to create the data path. Its function prototype is:
VLPath vlCreatePath(VLServer vlServer, VLDev vlDev
VLNode src, VLNode drn)
|
This code fragment creates a path if the device is unknown:
if ((path = vlCreatePath(svr, 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(svr, 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 vlServer, VLPath path) |
For example:
devicenum = vlGetDevice(svr, 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 vlServer, VLPath path, VLNodeId node) |
where:
| vlServer | 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 vlServer, VLPathList paths,
u_int count, VLUsageType ctrlusage,
VLUsageType streamusage)
|
where:
| vlServer | 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:
| |||
| streamusage | specifies usage for the data:
|
This example fragment sets up a path with shared controls and a locked stream:
if (vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE,
VL_LOCK) < 0)
{
vlPerror(_progName);
exit(1);
}
|
Use vlSelectEvents() to specify the events you want to receive. Its function prototype is:
int vlSelectEvents(VLServer vlServer, VLPath path, VLEventMask eventmask) |
where:
| vlServer | names the server to which the path is connected. | |
| path | specifies the data path. | |
| eventmask | specifies the event mask; Table 12-3 lists the possibilities. |
Table 12-3 lists and describes the VL event masks.
Symbol | Meaning |
|---|---|
VLStreamBusyMask | Stream is locked |
VLStreamPreemptedMask | Stream was grabbed by another application |
VLAdvanceMissedMask | Time was already reached |
VLSyncLostMask | Irregular or interrupted signal |
VLSequenceLostMask | Field or frame dropped |
VLControlChangedMask | A control has changed |
VLControlRangeChangedMask | A control range has changed |
VLControlPreemptedMask | Control of a node has been preempted, typically by another user setting VL_LOCK on a path that was previously set with VL_SHARE |
VLControlAvailableMask | Access is now available |
VLTransferCompleteMask | Transfer of field or frame complete |
VLTransferFailedMask | Error; transfer terminated; perform cleanup at this point, including vlEndTransfer() |
VLEvenVerticalRetraceMask | Vertical retrace event, even field |
VLOddVerticalRetraceMask | Vertical retrace event, odd field |
VLFrameVerticalRetraceMask | Frame vertical retrace event |
VLDeviceEventMask | Device-specific event, such as a trigger on a Galileo Video device |
VLDefaultSourceMask | Default source changed |
For example:
vlSelectEvents(svr, path, VLTransferCompleteMask); |
Event masks can be ORed together. For example:
vlSelectEvents(svr, path, VLTransferCompleteMask | VLTransferFailedMask); |
Transferring data to or from memory requires creating a ring 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 and drain node controls is explained separately in this section.
![]() | Note: All controls are available for all platforms unless otherwise noted. The reference “Galileo Video” includes Indigo2 Video and Indy Video, unless otherwise noted. |
Important data transfer controls for source nodes are summarized in Table 12-4. They should be set in the order in which they appear in the table.
Table 12-4. Data Transfer Controls for Source Nodes
Control | Values | Basic Usage |
|---|---|---|
VL_MUXSWITCH | See Table 12-5 | Determines physical input for path |
VL_TIMING | Default: timing produce VL_TIMING_525_SQ_PIX
| Set or get video timing For Betacam, MII, composite
tape formats: For D1 tape formats: For D2 tape formats: |
VL_SIZE | Coordinates | Set or get active unmodified video area |
VL_SYNC_SOURC E | Galileo Video: Indigo2 Video and Indy
Video: | Not applicable to VINO |
The use of VL_MUXSWITCH and VL_TIMING is explained in further detail in the following sections.
Use VL_MUXSWITCH to switch between physical inputs on a single path. Table 12-5 summarizes values for VL_MUXSWITCH, which vary, depending on the platform.
Table 12-5. VL_MUXSWITCH Values
Platform | Values |
|---|---|
Galileo Video | S-Video input 1: set 0; input 2: set 1; input 3: set 2 |
Indigo2 Video and Indy Video | Y/C (RCA jacks): set 0 |
VINO | Node VL_VINO_SRC_DV_IN: Node VL_VINO_SRC_AV_IN: |
For Indy Video, the default source depends on which input is active; that is, which input has equipment that is both plugged in and powered on. In other words, the VL assumes that you want to use the piece of equipment that is plugged in and powered on, without you having to tell it so. If the S-Video input is active, it is the default. If the composite input is active, it is the default. If both S-Video and composite equipment are inactive and the IndyCam is active (plugged in), the IndyCam is the default. Composite becomes the default video in two cases: if it is active or if all other inputs are inactive.
You can control the default by unplugging or plugging in equipment and/or turning equipment power on or off. For example:
set S-Video active by switching on the equipment plugged into the S-Video input
set composite active by switching off the equipment plugged into the S-Video input
Of course, you can change the settings—this just gives you an idea of what default to expect. If equipment is plugged in to all the inputs, the default VINO input is established by the precedence listed in top-down order in Table 12-6.
Table 12-6. Default Sources for VINO Inputs
Input | S-Video | Composite | IndyCam |
|---|---|---|---|
S-Video | Active | N/A | N/A |
Composite | Inactive | Active | N/A |
IndyCam | Inactive | Inactive | Active |
Composite | Inactive | Inactive | Inactive |
Table 12-7 summarizes VL_TIMING choices for combinations of nodes and mux switches for VINO.
Table 12-7. VINO Timing Choices
Node Value | VL_MUXSWITCH Value | Timing Choices |
|---|---|---|
VL_VINO_SRC_DV_IN
| VL_VINO_INDYCAM VL_VINO_CCIR601 | VL_TIMING_525_SQ_PIX (NTSC) VL_TIMING_525_SQ_PIX (NTSC) |
VL_VINO_SRC_AV_IN | VL_VINO_COMPOSITE VL_VINO_SVIDEO | VL_TIMING_525_SQ_PIX (NTSC) VL_TIMING_525_SQ_PIX (NTSC) |
Timing type expresses the timing of video presented to a source or drain. Table 12-8 summarizes dimensions for VL_TIMING.
Table 12-8. Dimensions for Timing Choices
|
|
| First Active Line (Offset=0) |
|---|---|---|---|
VL_TIMING_525_SQ_PIX (12.27 MHz) | 640 | 480 | 22 |
VL_TIMING_625_SQ_PIX (14.75 MHz) | 768 | 576 | 32 |
VL_TIMING_525_CCIR601 (13.50 MHz) | 720 | 480 | 1 |
VL_TIMING_625_CCIR601(13.50 MHz) | 720 | 576 | 1 |
VL_TIMING_525_SQ_PIX (12.27 MHz) | 640 | 480 | 2 |
Important data transfer controls for drain nodes are summarized in Table 12-9. They should be set in the order in which they appear in the table.
Table 12-9. Data Transfer Controls for Drain Nodes
Control | Basic Usage | Video Nodes | Memory Nodes | Screen Nodes |
|---|---|---|---|---|
VL_FORMAT | Video format on the physical connector |
|
| |
VL_TIMING | Video timing | See Table 12-4 for values | Not applicable | Not applicable |
VL_CAP_TYP E | Setting type of field(s) or frame(s) to capture; see “Interlacing” in Chapter 11 | Not applicable | VL_CAPTURE_NONINTERLEAVED | Not applicable |
VL_PACKING | Pixel packing (conversion) format | Not applicable | Changes pixel format of captured data; see Table 12-10 for values | Not applicable |
VL_ZOOM | Decimation or zoom factor (fraction) Galileo Video: VINO: | Not applicable | Decimation or zoom: resizes data to remain within limits | Decimation or zoom: resizes data to remain within limits |
VL_SIZE | Clipping size | Full size of video; read only | Clipped size | Clipped size |
VL_OFFSET | Position within larger area | Position of active region | Offset relative to video offset | Pan within the video |
VL_ORIGIN | Position within video | Not applicable | Not applicable | Screen position of first pixel displayed; not applicable to VINO |
VL_WINDOW | Setting window ID for video in a window | Not applicable | Not applicable | Window ID; not applicable to VINO |
VL_RATE | Field or frame transfer speed | Depends on capture type as specified by VL_CAP_TYPE | Not applicable | Not applicable |
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. For all devices, VL_PACKING must be set first. For VINO, set offset before size. 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.
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 will not be what you requested.
To specify the controls, use vlSetControl(), for which the function prototype is:
int vlSetControl(VLServer vlServer, VLPath vlPath,
VLNode node, VLControlType type,
VLControlValue * value)
|
The use of VL_FORMAT, VL_PACKING, VL_ZOOM, VL_SIZE, VL_OFFSET, VL_RATE, and VL_CAP_TYPE is explained in more detail in the following sections.
To specify video input and output formats of the video signal on the physical connector, use VL_FORMAT. Each video platform has a video format native to it; for example, YUV 4:2:2 is native to Galileo Video and RGB is native to Sirius Video. The native format is always the fastest for that platform. To discover the native format for your video platform, consult the release notes or other documentation for the product.
![]() | Note: To convert formats, use VL_PACKING, which is explained in the next section. |
When VL_FORMAT is applied to a source or drain that is a VL_MEM (memory) node, it selects the format of the video stored in memory. This may imply a software conversion of the video data after the transfer is completed.
Values for VL_FORMAT for Galileo Video are:
VL_FORMAT_RGB (output only)
VL_FORMAT_BETACAM (input and output)
VL_FORMAT_SMPTE_YUV (input and output)
To convert a video output format to another in memory, use the control VL_PACKING. Packing type expresses the packing in memory of the video data at the source or drain.
Packing types are summarized in Table 12-10, which shows the most significant byte on the left. An X means don't care; this bit is not used.
Table 12-10. Packing Types and Their Sizes and Formats
Type | Size | Format |
|---|---|---|
VL_PACKING_RGB_332_P | 8-bit word | BBGGGRRR (four pixels packed into a 32-bit word) |
VL_PACKING_RGBA_8 | 32-bit word | AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR |
VL_PACKING_RGB_8 | 24-bit word | XXXXXXXX BBBBBBBB GGGGGGGG RRRRRRRR |
VL_PACKING_Y_8_P | 8-bit word | YYYYYYYY (four pixels packed into a 32-bit word) |
VL_PACKING_YVYU_422_8 | 32-bit word | UUUUUUUU YYYYYYYY VVVVVVVV YYYYYYYY |
![]() | Note: The packing names follow the naming conventions used by the IRIS GL; other libraries such as the OpenGL may use different names. |
For example:
VLControlValue val; val.intVal = VL_PACKING_RGB; vlSetControl(svr, path, memdrn, VL_PACKING, &val); |
VL_ZOOM controls the expansion or decimation of the video image. Values greater than one expand the video; values less than one perform decimation. Figure 12-4 illustrates zooming and decimation.
![]() | Note: Zooming, that is, VL_ZOOM values greater than one, is not supported on VINO. |
VL_ZOOM takes a nonzero fraction as its argument; do not use negative values. For example, this fragment captures half-size decimation video to memory:
val.fractVal.numerator = 1;
val.fractVal.denominator = 2;
if (vlSetControl(server, memory_path, memory_drain_node, VL_ZOOM, &val)){
vlPerror("Unable to set zoom");
exit(1);
}
|
![]() | Caution: Not all video devices support all aspects of zooming. If you use a control on a video device that does not support it, a VLValueOutOfRange error is returned. Use vlGetControl() to show what your results were. |
![]() | Note: For a source, zooming takes place before blending; for a drain, blending takes place before zooming. |
This fragment captures half-size decimation video to memory, with clipping to 320 × 240 (NTSC size minus overscan).
val.fractVal.numerator = 1;
val.fractVal.denominator = 2;
if (vlSetControl(server, memory_path, memory_drain_node,
VL_ZOOM, &val))
{
vlPerror("Unable to set zoom");
exit(1);
}
val.xyVal.x = 320;
val.xyVal.y = 240;
if (vlSetControl(server, memory_path, memory_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, memory_path, video_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, memory_path, memory_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, memory_path, memory_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 12-5 illustrates clipping.
For example, to display PAL video in a 320 × 240 space, clip the image to that size, as shown in the following fragment:
VLControlValue value; |
value.xyval.x=320; value.xyval.y=240; vlSetControl(svr, 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.
VL_OFFSET operates on the unzoomed image; it does not change if the zoom factor is changed.
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(svr, path, drn, VL_OFFSET, &value); |
To capture the blanking region, set offset to a negative value.
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 12-11.
Table 12-11. VL_RATE Values (Items per Second)
VL_CAP_TYPE Value | VL_RATE Value |
|---|---|
VL_CAPTURE_NONINTERLEAVED only | NTSC: 10, 12, 20, 24, 30, 36, 40, 48, 50, 60 PAL: 5, 10, 15, 20, 25 |
VL_CAPTURE_INTERLEAVED, | NTSC: 5, 6, 10, 12, 15, 18, 20, 24, 25, 30 PAL: 10, 20, 30, 40, 50 |
Figure 12-6 shows the relationships between the source and drain zoom, size, offset, and origin.
To set up a window for live video on Galileo Video, Indigo2 Video, or Indy Video, follow these steps, as outlined in the example program simplev2s.c.
![]() | Note: This information does not apply to VINO. Because the video resident in the Indy workstation has no screen node, use the memory node. Capture the video and use the lrectwrite() function or the analogous X or OpenGL function. |
Open an X display window; for example:
if (!(dpy = XOpenDisplay("")))
exit(1);
|
Connect to the video daemon; for example:
if (!(svr = vlOpenVideo("")))
exit(1);
|
Create a window to show the video; for example:
vwin = XCreateSimpleWindow(dpy, RootWindow(dpy, 0), 10,
10, 640, 480, 0,
BlackPixel(dpy,DefaultScreen(dpy)),
BlackPixel(dpy, DefaultScreen(dpy));
XMapWindow(dpy, vwin);
XFlush(dpy);
|
Create a source node on a video device and a drain node on the screen; for example:
src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY); drn = vlGetNode(svr, VL_DRN, VL_SCREEN, VL_ANY); |
Create a path on the first device that supports it; for example:
if((path = vlCreatePath(svr, VL_ANY, src, drn)) < 0)
exit(1);
|
Set up the hardware for the path and define the path usage; for example:
vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE,
VL_SHARE);
|
Set the X window to be the drain; for example:
val.intVal = vwin; vlSetControl(svr, path, drn, VL_WINDOW, &val); |
Get X and VL into the same coordinate system; for example:
XTranslateCoordinates(dpy, vwin, RootWindow(dpy, DefaultScreen(dpy)), 0, 0,&x, &y, &dummyWin); |
Set the live video to the same location and size as the window; for example:
val.xyVal.x = x; val.xyVal.y = y; vlSetControl(svr, path, drn, VL_ORIGIN, &val); |
XGetGeometry(dpy, vwin, &dummyWin, &x, &y, &w, &h, &bw, &d); val.xyVal.x = w; val.xyVal.y = h; vlSetControl(svr, path, drn, VL_SIZE, &val); |
Begin the data transfer:
vlBeginTransfer(svr, path, 0, NULL); |
Wait until the user finishes; for example:
printf("Press return to exit.\n");
c = getc(stdin);
|
End the data transfer, clean up, and exit:
vlEndTransfer(svr, path); vlDestroyPath(svr, path); vlCloseVideo(svr); |
The processes for data transfer are:
creating a buffer for the frames (transfers involving memory)
registering the ring buffer with the path (transfers involving memory)
starting data transfer
reading data from the buffer (transfers involving memory)
Each process is explained separately.
Once you have specified frame parameters in a transfer involving memory (or have determined to use the defaults), create a buffer for the frames.
Like other libraries in the IRIS digital media development environment, the VL uses ring buffers. Ring buffers provide a way to read and write varying sizes of frames of 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 ring buffer is created, constraints are specified that control the total size of the data segment and the number of information buffers to allocate.
A head and a tail flag are automatically set in a ring 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 ring buffer is written to and all sectors are occupied, data transfer stops. The sector last written to remains locked down until it is released.
The ring buffer can accommodate data of varying size. You can specify a ring buffer at a fixed size or can determine the size of the data in the buffer.
To determine frame data size, use vlGetTransferSize(). Its function prototype is:
long vlGetTransferSize(VLServer svr, VLPath path) |
For example:
transfersize = vlGetTransferSize(svr, path); |
where transfersize is the size of the data in bytes.
To create a ring buffer for the frame data, use vlCreateBuffer(). Its function prototype is:
VLBuffer vlCreateBuffer(VLServer vlServer, VLPath path,
VLNode node, int numFrames)
|
where:
| VLBuffer | is the handle of the buffer to be created | |
| vlServer | 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 ring buffer | |
| numFrames | specifies the number of frames in the buffer |
For example:
buf = vlCreateBuffer(svr, path, src, 1); |
Use vlRegisterBuffer() to register the ring buffer with the data path. Its function prototype is:
int vlRegisterBuffer(VLServer vlServer, VLPath path,
VLNode memnodeid, VLBuffer buffer)
|
where:
| vlServer | names the server to which the path is connected | |
| path | specifies the data path | |
| memnodeid | specifies the memory node ID | |
| buffer | specifies the ring buffer handle |
For example:
vlRegisterBuffer(svr, path, drn, Buffer); |
To begin data transfer, use vlBeginTransfer(). Its function prototype is:
int vlBeginTransfer(VLServer vlServer, VLPath path,
int count, VLTransferDescriptor* xferDesc)
|
where:
| vlServer | names the server to which the path is connected | |
| path | specifies the data path | |
| count | specifies the number of transfer descriptors |
Tailor the data transfer by means of transfer descriptors. 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; |
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 |
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 12-12 lists the buffer-related calls.
Table 12-12. Buffer-Related Calls
Call | Purpose |
|---|---|
vlGetNextValid() | Returns a handle on the next valid frame of data |
vlGetLatestValid() | Reads only the most current frame in the buffer, discarding the rest |
vlPutValid() | Puts a frame into the valid list (memory to video) |
vlPutFree() | Puts a valid frame 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 12-7 illustrates the difference between vlGetNextValid() and vlGetLatestValid(), and their interaction with vlPutFree().
Table 12-13 lists the calls that extract information from a buffer.
Table 12-13. Calls for Extracting Data from a Buffer
Call | Purpose |
|---|---|
vlGetActiveRegion() | Gets a pointer to the data region of the buffer (video to memory); called aftervlGetNextValid() 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(svr, path, memnode1); vlRegisterBuffer(svr, path, memnode1, buffer); vlBeginTransfer(svr, path, 0, NULL); info = vlGetNextValid(svr, buffer); /* OR vlGetLatestValid(svr, buffer); */ dataptr = vlGetActiveRegion(svr, buffer, info); /* use data for application */ … vlPutFree(svr, buffer); |
For memory-to-video transfer, use:
buffer = vlCreateBuffer(svr, path, memnode1); vlRegisterBuffer(svr, path, memnode1, buffer); vlBeginTransfer(svr, path, 0, NULL); buffer = vlGetNextFree(svr, buffer, bufsize); /* fill buffer with data */ … vlPutValid(svr, 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 vlServer, VLBuffer vlBuffer) |
Use vlGetLatestValid() to read only the most current frame in the buffer, discarding the rest. Its function prototype is:
VLInfoPtr vlGetLatestValid(VLServer vlServer, VLBuffer vlBuffer) |
After removing interesting data, return the buffer for use with vlPutFree() (video to memory). Its function prototype is:
int vlPutFree(VLServer vlServer, VLBuffer vlBuffer) |
Use vlGetNextFree() to get a free buffer to which to write data. Its function prototype is:
VLInfoPtr vlGetNextFree(VLServer vlServer,
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 vlServer, 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 vlServer,
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 vlServer,
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 vlServer,
VLBuffer vlBuffer, VLInfoPtr ptr)
|
To end data transfer, use vlEndTransfer(). Its function prototype is:
int vlEndTransfer(VLServer vlServer, VLPath path) |
To accomplish the necessary cleanup to exit gracefully, use:
for transfer involving memory: vlDeregisterBuffer(), vlDestroyPath(), vlDestroyBuffer()
for all transfers: vlCloseVideo()
The function prototype for vlDeregisterBuffer() is:
int vlDeregisterBuffer(VLServer vlServer, VLPath path,
VLNode memnodeid, VLBuffer ringbufhandle)
|
where:
| vlServer | is the server handle | |
| path | is the path handle | |
| memnodeid | is the memory node ID | |
| ringbufhandle | is the ring buffer handle |
The function prototypes for vlDestroyPath(), vlDestroyBuffer() and vlCloseVideo() are, respectively:
int vlDestroyPath(VLServer vlServer, VLPath path) int vlDestroyBuffer(VLServer vlServer, VLBuffer vlBuffer) int vlCloseVideo(VLServer vlServer) |
This example ends a data transfer that used a buffer:
vlEndTransfer(svr, path); vlDeregisterBuffer(svr, path, memnodeid, buffer); vlDestroyPath(svr, path); vlDestroyBuffer(svr, buffer); vlCloseVideo(svr); |
The example code in this section illustrates:
a simple screen application
a video-to-memory frame grab
a memory-to-video frame output
a continuous frame capture
Source code for these programs is in /usr/people/4Dgifts/examples/dmedia/video/vl.
![]() | Note: To simplify the code, these examples do not check returns. The programmer should, however, always check returns. |
Example 12-1 shows how to send live video to the screen (for systems that have a video output port).
Example 12-1. Sending Live Video to the Screen: simplev2s.c
/*
* File: simplev2s.c
*
* Usage: simplev2s
*
* Description: Simplev2s demonstrates live video to screen.
* This application only runs on video hardware
* that has a video output port. It will not run
* on a VINO video board.
*
* Functions: SGI Video Library functions used
*
* vlOpenVideo()
* vlGetNode()
* vlCreatePath()
* vlSetupPaths()
* vlSetControl()
* vlBeginTransfer()
* vlEndTransfer()
* vlDestroyPath()
* vlCloseVideo()
*/
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <Xm/MwmUtil.h>
#include <X11/Xutil.h>
#include <vl/vl.h>
main(int argc, char **argv)
{
VLServer svr;
VLPath path;
Display *dpy;
Window vwin;
VLNode src, drn;
VLControlValue val;
char *progname, *ptr;
int x, y, c;
uint w, h, bw, d;
Window dummyWin;
XSizeHints size_hints;
XClassHint class_hints;
/* get basename of argv */
if ((ptr = strrchr(*argv, '/')) != NULL) progname = ++ptr;
else progname = *argv;
/* Open an X display */
if (!(dpy = XOpenDisplay("")))
exit(1);
/* Connect to the video daemon */
if (!(svr = vlOpenVideo("")))
exit(1);
/* Create a window to show the video */
vwin = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
10, 10, 640, 480, 0,
BlackPixel(dpy, DefaultScreen(dpy)),
BlackPixel(dpy, DefaultScreen(dpy)));
/* Ignore window manager placement set the window to 10, 10 */
size_hints.flags = USPosition;
size_hints.x = 10;
size_hints.y = 10;
/* set class properties for 4Dwm desktop */
class_hints.res_name = progname;
class_hints.res_class = progname;
XSetClassHint(dpy, vwin, &class_hints);
XSetWMNormalHints(dpy, vwin, &size_hints);
XMapWindow(dpy, vwin);
XFlush(dpy);
/* Create a source node on a video device */
src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
/* Create a drain node on the screen */
drn = vlGetNode(svr, VL_DRN, VL_SCREEN, VL_ANY);
/* Create a path on the first device that supports it */
if((path = vlCreatePath(svr, VL_ANY, src, drn)) < 0)
exit(1);
/* Set up the hardware for and define the usage of the path */
vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE, VL_SHARE);
/* Set the X window to be the drain */
val.intVal = vwin;
vlSetControl(svr, path, drn, VL_WINDOW, &val);
/* Get X and VL into the same coordinate system */
XTranslateCoordinates(dpy, vwin, DefaultRootWindow(dpy),
0, 0,&x, &y, &dummyWin);
/* Set the live video to the same location and size as the X window */
val.xyVal.x = x;
val.xyVal.y = y;
vlSetControl(svr, path, drn, VL_ORIGIN, &val);
XGetGeometry(dpy, vwin, &dummyWin, &x, &y, &w, &h, &bw, &d);
val.xyVal.x = w;
val.xyVal.y = h;
vlSetControl(svr, path, drn, VL_SIZE, &val);
/* Begin the data transfer */
vlBeginTransfer(svr, path, 0, NULL);
/* Wait until the user presses a key */
printf("Press return to exit.\n");
c = getc(stdin);
/* End the data transfer */
vlEndTransfer(svr, path);
/* Clean up and exit */
vlDestroyPath(svr, path);
vlCloseVideo(svr);
}
|
Example 12-2 demonstrates video frame grabbing.
Example 12-2. Video Frame Grabbing: simplegrab.c
/*
* File: simplegrab.c
* Usage: simplegrab
* Description: simplegrab grabs a video frame to memory and screen
* Functions: IRIS Video Library functions used
*
* vlOpenVideo()
* vlGetNode()
* vlCreatePath()
* vlSetupPaths()
* vlSetControl()
* vlCreateBuffer()
* vlRegisterBuffer()
* vlGetActiveRegion()
* vlGetNextValid()
* vlPutFree()
* vlBeginTransfer()
* vlEndTransfer()
* vlDeregisterBuffer()
* vlDestroyPath()
* vlDestroyBuffer()
* vlCloseVideo()
* vlPerror()
*/
#include <stdlib.h>
#include <stdio.h>
#include <gl/gl.h>
#include <dmedia/vl.h>
char *_progName;
/* Report errors */
void
error_exit(void)
{
vlPerror(_progName);
exit(1);
}
void
main(int argc, char **argv)
{
VLServer svr;
VLPath path;
VLNode src, drn;
VLControlValue val;
VLBuffer buffer;
VLInfoPtr info;
char *dataPtr;
int c;
int xsize;
int ysize;
long win;
_progName = argv[0];
foreground();
/* Connect to the daemon */
if (!(svr = vlOpenVideo("")))
error_exit();
/* Set up a drain node in memory */
drn = vlGetNode(svr, VL_DRN, VL_MEM, VL_ANY);
/* Set up a source node on any video source */
src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
/* Create a path using the first device that will support it */
path = vlCreatePath(svr, VL_ANY, src, drn);
/* Set up the hardware for and define the usage of the path */
if ((vlSetupPaths(svr, (VLPathList)&path, 1,
VL_SHARE, VL_SHARE)) < 0)
error_exit();
/* Set the packing to RGB */
val.intVal = VL_PACKING_RGB_8;
vlSetControl(svr, path, drn, VL_PACKING, &val);
/* Get the video size */
vlGetControl(svr, path, drn, VL_SIZE, &val);
xsize = val.xyVal.x;
ysize = val.xyVal.y;
/* Set up and open a GL window to display the data */
prefsize(xsize,ysize);
win = winopen("Simplegrab Window");
RGBmode();
pixmode(PM_TTOB, 1);
gconfig();
/* Create and register a buffer for 1 frame */
buffer = vlCreateBuffer(svr, path, drn, 1);
if (buffer == NULL)
error_exit();
vlRegisterBuffer(svr, path, drn, buffer);
/* Begin the data transfer */
if (vlBeginTransfer(svr, path, 0, NULL))
error_exit();
/* Wait for a frame */
do {
info = vlGetNextValid(svr, buffer);
} while (!info);
/* Get a pointer to the frame */
dataPtr = vlGetActiveRegion(svr, buffer, info);
/* Write the data to the screen */
lrectwrite(0,0, xsize-1, ysize-1, (ulong *)dataPtr);
/* Finished with frame, unlock the buffer */
vlPutFree(svr, buffer);
/* End the data transfer */
vlEndTransfer(svr, path);
/* Wait until the user presses a key */
printf("Press <Enter> to exit: ");
c = getc(stdin);
/* Cleanup before exiting */
vlDeregisterBuffer(svr, path, drn, buffer);
vlDestroyBuffer(svr, buffer);
vlDestroyPath(svr, path);
vlCloseVideo(svr);
}
|
Example 12-3 sends a frame to the video output (for systems that have a video output port).
Example 12-3. Frame Output: simplem2v.c
/*
* Files: simplem2v.c
*
* Usage: simplem2v <filename>
*
* Description: Simplem2v sends a frame of image data from memory
* to the video output. Image data must be in YUV422
* format. Images in this format may be generated by
* running the vidtomem application with the -r option
* on an Indy Video board.
* Simplem2v only runs on video hardware that has a
* video output port. It will not run on a VINO video
* board.
*
*
* Functions: SGI Video Library functions used
*
* vlOpenVideo()
* vlGetNode()
* vlCreatePath()
* vlSetupPaths()
* vlRegisterBuffer()
* vlCreateBuffer()
* vlGetTransferSize()
* vlGetNextFree()
* vlGetActiveRegion()
* vlBufferDone()
* vlBeginTransfer()
* vlEndTransfer()
* vlDeregisterBuffer()
* vlDestroyBuffer()
* vlDestroyPath()
* vlCloseVideo()
* vlGetErrno()
* vlPerror()
* vlStrError()
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/errno.h>
#include <dmedia/vl.h>
#define MIN(x,y) ((x>y)?y:x)
extern int errno;
main(int argc, char **argv)
{
VLServer svr;
VLPath MEMtoVIDPath;
VLNode src, drn;
VLBuffer buf;
VLInfoPtr info;
struct stat status_buffer;
char *dataPtr;
ulong transferSize;
int ret, fd;
int c;
char *_progName;
char *fileName;
_progName = argv[0];
if (argc != 2)
{
fprintf(stderr,"%s <filename>\n", _progName);
exit(1);
}
fileName = argv[1];
/* Connect to the daemon */
if (!(svr = vlOpenVideo("")))
{
fprintf(stderr,"%s: can't open video: %s\n", _progName,
vlStrError(vlGetErrno()));
exit(1);
}
/* Set up a source node in memory */
src = vlGetNode(svr, VL_SRC, VL_MEM, VL_ANY);
/* Set up a video drain node on the first device that has one */
drn = vlGetNode(svr, VL_DRN, VL_VIDEO, VL_ANY);
/* Create a path using the selected devices */
MEMtoVIDPath = vlCreatePath(svr, VL_ANY, src, drn);
/* Set up the hardware for and define the usage of the path */
if (vlSetupPaths(svr, (VLPathList)&MEMtoVIDPath, 1, VL_SHARE, VL_SHARE)<0)
{
fprintf(stderr,"%s: can't setup path: %s\n", _progName,
vlStrError(vlGetErrno()));
exit(1);
}
/* Find out what size this path supports */
transferSize = vlGetTransferSize(svr,MEMtoVIDPath);
/* Create a ring buffer for the data transfers */
buf = vlCreateBuffer(svr, MEMtoVIDPath, src, 1);
/* Associate the ring buffer with the path */
vlRegisterBuffer(svr, MEMtoVIDPath, src, buf);
/* Get the next free frame in the buffer, reserve it for data */
do
{
info = vlGetNextFree(svr, buf, transferSize);
} while (!info && !vlBufferDone(buf));
/* Get a pointer to where the data will go */
dataPtr = vlGetActiveRegion(svr, buf, info);
/* Open raw YUV data file */
fd = open(fileName, O_RDONLY);
if (!fd)
{
fprintf(stderr,"%s: cannot open file %s.\n", _progName, fileName);
exit(1);
}
/* Get the file's size (image size of this data)*/
if (fstat(fd,&status_buffer) == -1)
{
perror(fileName);
exit(1);
}
/* Make sure the hardware supports this image size */
if (status_buffer.st_size != transferSize)
{
fprintf(stderr,"%s: The image is not the right size for this device\n",
_progName);
exit(1);
}
/* Read in the data */
ret = read(fd, dataPtr, transferSize);
close(fd);
/* Check the size of the data read in */
if (ret != transferSize)
{
fprintf(stderr, "%s: Unable to read the image data\n", _progName);
exit(1);
}
/* Put the data into the ring buffer */
vlPutValid(svr, buf);
/* Begin the data transfer */
vlBeginTransfer(svr, MEMtoVIDPath, 0, NULL);
/* Wait until user presses a key */
printf("Hit return to exit.\n");
c = getc(stdin);
/* End the data transfer */
vlEndTransfer(svr, MEMtoVIDPath);
/* Clean up and exit */
vlDeregisterBuffer(svr, MEMtoVIDPath, src, buf);
vlDestroyPath(svr, MEMtoVIDPath);
vlDestroyBuffer(svr, buf);
vlCloseVideo(svr);
}
|
Example 12-4 demonstrates continuous frame capture.
Example 12-4. Continuous Frame Capture: simplecapt.c
/*==================A Simple Continuous Capture Application==========
*
*
* File: simpleccapt.c
*
* Usage: simpleccapt
*
* Description: simpleccapt captures a stream of video to memory
*
* Functions: IRIS Video Library functions used
*
* vlOpenVideo()
* vlGetNode()
* vlCreatePath()
* vlSetupPaths()
* vlSetControl()
* vlCreateBuffer()
* vlRegisterBuffer()
* vlGetActiveRegion()
* vlGetNextValid()
* vlPutFree()
* vlBeginTransfer()
* vlEndTransfer()
* vlDeregisterBuffer()
* vlDestroyPath()
* vlDestroyBuffer()
* vlCloseVideo()
* vlPerror()
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <gl/gl.h>
#include <dmedia/vl.h>
char *_progName;
/* Report errors */
void
error_exit(void)
{
vlPerror(_progName);
exit(1);
}
void
main(int argc, char **argv)
{
VLServer svr;
VLPath path;
VLNode src, drn;
VLControlValue val;
VLBuffer buffer;
VLInfoPtr info;
char *dataPtr;
int c;
int xsize;
int ysize;
long win;
_progName = argv[0];
foreground();
/* Connect to the daemon */
if (!(svr = vlOpenVideo("")))
error_exit();
/* Set up a drain node in memory */
drn = vlGetNode(svr, VL_DRN, VL_MEM, VL_ANY);
/* Set up a source node on any video source */
src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
/* Create a path using the first device that will support it */
path = vlCreatePath(svr, VL_ANY, src, drn);
/* Set up the hardware for and define the usage of the path */
if ((vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE, VL_SHARE)) < 0)
error_exit();
/* Set the packing to RGB */
val.intVal = VL_PACKING_RGB_8;
vlSetControl(svr, path, drn, VL_PACKING, &val);
/* Get the video size */
vlGetControl(svr, path, drn, VL_SIZE, &val);
xsize = val.xyVal.x;
ysize = val.xyVal.y;
/* Set up and open a GL window to display the data */
prefsize(xsize,ysize);
win = winopen("Simpleccapt Window");
RGBmode();
pixmode(PM_TTOB, 1);
gconfig();
/* Create and register a buffer for 1 frame */
buffer = vlCreateBuffer(svr, path, drn, 1);
if (buffer == NULL)
error_exit();
vlRegisterBuffer(svr, path, drn, buffer);
/* Begin the data transfer */
if (vlBeginTransfer(svr, path, 0, NULL))
error_exit();
printf("Type <control-c> to exit.\n");
for(;;) {
do {
sginap(1); /* wait a tick */
info = vlGetNextValid(svr, buffer);
} while (!info);
/* Get a pointer to the frame */
dataPtr = vlGetActiveRegion(svr, buffer, info);
/* Write the data to the screen */
lrectwrite(0,0, xsize-1, ysize-1, (ulong *)dataPtr);
/* Finished with frame, unlock the buffer */
vlPutFree(svr, buffer);
}
/* End the data transfer */
vlEndTransfer(svr, path);
/* Cleanup before exiting */
vlDeregisterBuffer(svr, path, drn, buffer);
vlDestroyBuffer(svr, buffer);
vlDestroyPath(svr, path);
vlCloseVideo(svr);
}
|