This chapter explains how to use buffers for data transfer, set execution times, and end data transfer, in these sections:
The VL supports two buffering mechanisms for capturing or playing back video:
VL buffers: the original buffering mechanism supported by the VL and specific to it
Digital Media Buffers (DMbuffers): a buffering mechanism allowing video data to be exchanged among video, compression, and graphics devices
For OCTANE, this buffering mechanism is supported by the Video, Image Converter (dmIC), and Movie Libraries. It is available with IRIX 6.4 and subsequent releases.
![]() | Note: For complete information on DMbuffers and digital media image converters, see the Digital Media Programming Guide. |
In general, VL buffers and DMbuffers differ in the following ways:
buffer structure
VL buffers are modeled after a ring buffer. The order of segments (buffers) in the ring is inflexible, and care must be taken to ensure that items are obtained and returned in the same order. For example, buffers obtained with vlGetNextValid() must be returned using vlPutFree() in the same order. Order and allocation of ring segments are intricately related.
All operations on a VL buffer operate in FIFO order. That is, the first element retrieved by vlGetNextValid() is the first returned by vlPutFree(). This function does not take an element as a parameter and always puts back the oldest outstanding element.
DMbuffers, in contrast, are contained in a DMbufferpool. The pool itself is unordered; buffers can be obtained from and returned to the pool in any order. Ordering is achieved by a first-in-first-out queue, and is maintained only while the buffers are in the queue. The application or library is free to impose any processing order on buffers, once they have been dequeued.
buffer size and alignment
The Video Library is responsible for ensuring that VL buffers are of the appropriate size and alignment for the video device, and for allocating the buffers in the vlCreateBuffer() call. Except in rare cases, applications cannot modify these attributes to suit the needs of another library or device.
Because DMbuffers can be used with libraries and devices besides video, the application queries each library for its buffering requirements. The exact DMbufferpool requirements are the union of all requested constraints and are enforced when the pool is created. For example, if one library requests alignment on 4K boundaries and another requests alignment on 16K boundaries, the 16K alignment is used. By specifying its own pool requirements list, the application can set minimum buffer sizes (such as for in-place processing of video) or cache policies.
buffers and memory nodes
With VL buffers, a particular ring buffer is strictly tied to a particular memory node; a DMbufferpool is not necessarily tied to a memory node. A memory source node can receive DMbuffers allocated from any DMbufferpool that meets the memory node's pool requirements. Memory drain nodes obtain DMbuffers from a DMbufferpool specified by the application; this pool is fixed for the duration of a transfer.
Each buffering mechanism has a set of API functions for creating, registering, and manipulating buffers. A mismatch between a buffer mechanism and an API call, for example, applying a VL buffer call to a DMbuffer, results in a VLAPIConflict error return.
Applications can use either VL buffers or DMbuffers, as long as a memory node is used with only one buffering mechanism at a time. If an application uses multiple memory paths, each path can use a different buffering mechanism. To switch buffering mechanisms, the VL path should be torn down and reconstructed.
Table 5-1 shows correspondences between VL buffer and DMbuffer API functions.
Table 5-1. VL Buffer and DMBuffer API Functions
VL Buffer API | dmBuffer API |
---|---|
vlCreateBuffer() | dmBufferCreatePool() |
vlPutValid() | vlDMBufferPutValid() |
vlRegisterBuffer() | vlDMBufferPoolRegister() |
vlDeregisterBuffer() | No equivalent |
vlPutFree() | dmBufferFree() |
vlGetNextValid() | vlDMBufferGetValid() |
vlGetLatestValid() | No equivalent |
vlGetFilled() | vlGetFilledByNode() |
vlDestroyBuffer() | dmBufferDestroyPool() |
vlBufferGetFd() | dmBufferGetPoolFD() dmBufferSetPoolSelectSize() vlNodeGetFd() |
vlBufferAdvise() | dmSetPoolDefaults() |
vlBufferReset() | vlDMBufferNodeReset() |
vlBufferDone() | Not applicable |
The DMbuffer is created through the dmBufferCreatePool() routine and is associated with a memory node by the dmPoolRegister() routine.
When the OCTANE Personal Video option transfers data from the Video Library to an application, it places data in a buffer element and marks the element as valid. The application can retrieve the element through the vlDMBufferGetValid() routine. When the application is done, it uses the dmBufferFree() routine to alert the video device that the buffer element can be reused. For complete details on using DMbuffers, see Chapter 5 of the Digital Media Programming Guide (007-1799-060 or later).
This section explains
Before a DMbufferpool is created, you must obtain the pool requirements of any library that will interact with the pool. Pool requirements are maintained in a DMparams list, created using dmParamsCreate() and initialized by calling dmBufferSetPoolDefaults(). See Chapter 3 in the Digital Media Programming Guide for an overview of DMparams. The function prototype for this call is
DMstatus dmBufferSetPoolDefaults(DMparams *poolParams, int bufferCount, int bufferSize, DMboolean cacheable, DMboolean mapped) |
where
poolParams | specifies the DMparams list to use for gathering pool requirements | |
bufferCount | specifies the number of buffers the pool should contain | |
bufferSize | specifies the size of each buffer in the pool | |
cacheable | specifies whether buffers allocated from the pool can be cached (DM_TRUE) or not (DM_FALSE). For more information on caching, see “Caching” in Chapter 8. | |
mapped | specifies whether the memory allocated for the pool should be mapped as soon as the pool is created (TRUE), or only when dmBufferMapData() is called (FALSE) If an application requires a pointer to buffer contents, for example, to process or store the contents to disk, then the pool should be created mapped. This option improves the performance of the dmBufferMapData() call. |
The Video Library pool requirements are obtained by calling vlDMBufferGetParams() on a memory node:
int vlDMBufferGetParams(VLServer svr, VLPath path, VLNode node, DMparams *params) |
where
svr | names the server to which the path is connected | |
path | specifies the data path containing the memory node | |
node | specifies the memory node with which the DMbufferpool will be used | |
params | specifies the pool requirements list |
As with similar calls in other libraries, vlDMBufferGetParams takes as input a DMparams list initialized by dmBufferSetPoolDefaults, and possibly other libraries' pool requirements functions. On output, the Video Library's requirements are merged with the input requirements.
After all libraries that will use the pool have been queried for their requirements, the application can create a DMbufferpool by calling dmBufferCreatePool. Its function prototype is
DMstatus dmBufferCreatePool(const DMparams *poolParams, DMbufferpool *returnPool) |
where
poolParams | specifies the requirements for the pool | |
returnPool | points to a location where the DMbufferpool handle will be stored |
If the application captures video data, it specifies the DMbufferpool the memory node should use by calling vlDMBufferPoolRegister:
int vlDMBufferPoolRegister(VLServer svr, VLPath path, VLNode node, DMbufferpool pool) |
where
svr | specifies the server that the path is attached to | |
path | specifies the path containing the memory node | |
node | specifies the memory node | |
pool | specifies the pool that the memory node should use |
When the video device is ready to capture a new frame or field, it will allocate a DMbuffer from the specified pool, place the field or frame in it, then send the buffer to the application.
To begin data transfer (for either type of buffer), 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
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; |
After the transfer has been started, captured video may be retrieved using vlDMBufferGetValid:
int vlDMBufferGetValid(VLServer svr, VLPath path, VLNode node, DMbuffer* dmbuffer) |
where
svr | specifies the server the path is attached to | |
path | specifies the path on which data is received from | |
node | specifies the memory drain node data is received from | |
dmbuffer | points to a location where a DMbuffer handle is stored |
The DMbuffer handle returned by vlDMBufferGetValid is an opaque reference to the captured video. dmBufferMapData can be used to obtain a pointer to the actual image data so that it can be processed or written to disk. dmBufferMapData does not have to be called if the buffer will be directly sent to another device or library.
Applications can use vlDMBufferPutValid to send buffers to a video device:
int vlDMBufferPutValid(VLServer svr, VLPath path, VLNode node, DMbuffer dmbuffer) |
where
svr | specifies the server to which the path is attached | |
path | specifies the path on which video is sent | |
node | specifies the memory source node to send the buffer to | |
dmbuffer | specifies the buffer to send |
The DMbuffer may have been obtained from another library, such as dmIC, or generated by the application itself. See Chapter 5 in the Digital Media Programming Guide for an explanation of how to allocate a DMbuffer from a DMbufferpool.
Once the application is done with a buffer, it should call dmBufferFree to indicate that it no longer intends to use the buffer. After all users of a buffer have called dmBufferFree on it, the buffer is considered free to be reallocated. The Video Library never implicitly releases the application's access to a buffer. Consequently, an application can send the same buffer to a memory node multiple times, or hold a captured image for an indefinite period.
The processes for data transfer using VL buffers are as follows:
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 VL 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_INTERLEAVED
fields if the capture type is anything else
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 5-2 shows the relationship between capture type and minimum VL buffer size.
Table 5-2. 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 Personal 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); |
Start data transfer the same way as for DMbuffers; see “Starting Data Transfer” in “Transferring Video Data Using DMbuffers.”
If your application uses a VL buffer, use various VL calls for reading frames, getting pointers to active buffers, freeing buffers, and other operations. Table 5-3 lists the buffer-related calls.
Table 5-3. 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 5-1 illustrates the difference between vlGetNextValid() and vlGetLatestValid().
Table 5-4 lists the calls that extract information from a buffer.
Table 5-4. 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); |
To read the frames to memory from the buffer, 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) |
To send frames from memory to video, 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. |
To get DMediaInfo and Image Data from the buffer, 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 for either VL buffers or DMbuffers, 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. Memory nodes 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(), dmBuffer(), and vlCloseVideo() are, respectively
int vlDestroyPath(VLServer vlSvr, VLPath path) int vlDestroyBuffer(VLServer vlSvr, VLBuffer vlBuffer) int vlGetFilledByNode(VLServer vlSvr, VLPath path, VLNode node); int vlDMBufferNodeReset(VLServer vlSvr, VLPath path, VLNode node); int vlCloseVideo(VLServer vlSvr) |
where vlSvr specifies the server to which the application is attached, and path and node identify the memory node on which information is requested.
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); |
For DMbuffers, vlDMBufferPoolDeregister disassociates a DMbufferpool from a memory node. It should be called to clean up the memory node or allow a new DMbufferpool to be used after a transfer has been stopped.
Once the application is done with a DMbufferpool, the pool should be destroyed using the dmBufferDestroyPool call.
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.
a memory-to-video frame output simplem2v.c
This program sends a frame to the video output.
a 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. |
See Chapter 7 for a description of eventex.c.
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.