Chapter 6. Video Real-Time Capture and Playback
Prev |  | Next

## Chapter 6. Video Real-Time Capture and Playback

The Indigo2 IMPACT Video VGI1 memory nodes are capable of full video-rate capture and playback to the Video Library buffers. This chapter explains how to optimize capture or playback to system memory or disk.

- Video Library buffers

- caching

- buffer alignment

- direct I/O to disk

- `syssgi`

- asynchronous I/O

This chapter concludes with descriptions of examples.

## Video Library Buffers

Data transfer between the VL and an application takes place through a VL buffer. This buffer is created through the `vlCreateBuffer()` routine and is associated with a memory node by the `vlRegisterBuffer()` routine. A VL buffer is composed of a number of elements of field or frame size, depending on the capture type. The number of elements comprising a buffer is specified to `vlCreateBuffer()`.

When Indigo2 IMPACT Video 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 `vlGetNextValid()` and `vlGetLatestValid()` routines. When the application is done, it uses the `vlPutFree()` routine to alert the video device that the buffer element can be reused.

When Indigo2 IMPACT Video transfers data from the application to the Video Library, the application retrieves an empty buffer using `vlGetNextFree()`. After placing data in it, the application marks the buffer valid using the `vlPutValid()` routine. When the video device is done reading from the buffer, it marks the buffer as free.

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.

## Caching

Use the `vlBufferAdvise()` routine to mark a VL buffer as cacheable or not. It has the following prototype:

    int vlBufferAdvise(VLBuffer buffer, int advice)

where

buffer |  | specifies the ring buffer to be advised
advice |  | specifies the type of advisory being made: VL_BUFFER_ADVISE_NOACCESS marks the buffer as non-cacheable VL_BUFFER_ADVISE_ACCESS marks the buffer as cacheable

Marking the buffer non-cacheable indicates that the CPU cache does not have to be flushed or invalidated when data is read or written to system memory via DMA. However, any access to the buffer through the CPU must then bypass the cache and must always go to system memory. This arrangement can severely degrade the performance of an application that directly manipulates the video data.

Consequently, marking a buffer cacheable or noncacheable is application-dependent. In general:

- If the application manipulates the data, even if it is only to copy the data into or out of another region of system memory, the buffer should be set cacheable. This setting is the default for a buffer.

- If the application does not manipulate data, and all transfer is done strictly through DMA, then performance is optimized by setting the buffer to noncacheable. This is the case, for example, when video is read into the ring buffer and then written directly to disk with raw or direct I/O.

  | Note: If raw or direct I/O is not used, the data is first copied into the filesystem cache. In that case, the buffer should be kept cacheable.

## Buffer Alignment

The performance of the `memcpy()` and `bcopy()` routines is greatly affected by the alignment of the source and destination buffers. For copy operations between buffers with the same alignment, throughput is approximately 400% greater than between buffers with mismatched alignments. On a 200 MHz R4400 IMPACT system, aligned copies typically yield 80 MB per second. In contrast, unaligned copies yield approximately 21 MB per second.

For `memcpy()` and `bcopy()`, the source and target buffers can be considered aligned if the following condition is met:

    (src % 4) == (dest % 4)

In other words, the source and destination buffer addresses are equally distant from a word boundary.

Because the VL buffers used with the Indigo2 IMPACT Video device are page-aligned, performance is maximized if the application's buffers are word-aligned. Note that the memory allocation routines such as `malloc()` return double-word (64-bit aligned) buffers.

## Direct I/O to Disk

Capture or playback from a disk subsystem can be greatly improved by using direct I/O. Direct I/O bypasses the filesystem's buffer cache, eliminating a data copy and other overhead. The buffer can also be marked noncacheable, yielding further performance gains.

Because the filesystem cache is bypassed, device buffer alignment and block size restrictions fall onto the application. These restrictions can be obtained using

    fcntl(int fd, F_DIOINFO, struct dioattr *dioattr)

The device can, for example, require that the buffer be page-aligned. Disk devices usually require that the buffer's size be a multiple of 512 bytes (the disk sector size), or a multiple of the stripe size.

In addition, device performance can be improved with certain alignments or sizes. For example, a device operating on a non-page-aligned buffer can internally break the request into a nonaligned part and an aligned part, yielding the overhead of two requests instead of one. In striped disk subsystems, performance is usually improved by reading or writing entire stripes at a time.

VL buffer elements used with the Indigo2 IMPACT Video device are always page-aligned, which satisfies the alignment constraints of most devices.

The VL_MGV_BUFER_QUANTUM control is provided so that an application can specify the block size that should be applied to a video unit. (The video unit is a field or frame, depending on the capture type.) For example, setting this control to 512 rounds the frame or field size, as reported by `vlGetTransferSize()`, up to a multiple of 512. This control should be set to a multiple of the block size returned by `fcntl(fd, F_DIOINFO, ...)`, or to the optimal block size for the device.

When VL_MGV_BUFFER_QUANTUM is set to a value other than 1, the video data is padded at the end with random values. Consequently, it is important to use the same value for VL_MGV_BUFFER_QUANTUM on capture and on playback. Making the value the same can be a problem if a file is copied from one device to another with a different allowable block size. It is recommended that the control be set to a common multiple of the allowable sizes. For example, 4096 satisfies most devices. Otherwise, the file may need to be reformatted.

## syssgi

Some of the standard I/O routines support files sizes only up to 2 GB because file position is expressed as a signed integer. `lseek`, for example, only operates up to a 2 GB range. (Note that it is possible to use the `read` or `write` system calls to read or write past the 2 GB mark, up to the filesystem size).

The `syssgi` system call can be used to read or write raw disk partitions greater than 2 GB when used with the following parameters:

    int syssgi(int request, int fd, char *data, int blockoffset, int numblocks)

where

request |  | is SGI_READB for a read operation or SGI_WRITEB for a write operation
fd |  | is a file descriptor of a character special device, as obtained by the `open` system call
data |  | points to the buffer to be written from or read to
blockoffset |  | is the block position where reading or writing should commence
numblocks |  | is the number of blocks to read or write starting at blockoffset

Note that `syssgi` operates in units of device blocks as opposed to bytes. For disk subsystems, a block is usually 512 bytes, allowing 240 bytes of disk space to be addressed.

As with direct I/O, the application is responsible for ensuring that the data buffer is properly aligned and that block size constraints are followed.

## Asynchronous I/O

Asynchronous I/O allows an application to process multiple read or write requests simultaneously. On Silicon Graphics platforms, asynchronous I/O is available through the aio facility. The aio64 facility additionally supports 64-bit file sizes and offsets.

Because multiple I/O requests might be outstanding when asynchronous
I/O is used, the round-trip delay between making a request, having it serviced, and issuing another request is removed. Asynchronous I/O also eliminates any process-scheduling delay between these steps. In addition, the device being read from or written to might be able to optimize performance by carrying out the requests simultaneously.

The following points should be kept in mind when using asynchronous
I/O with VL buffers:

- The VL buffer is a first-in first-out mechanism. When putting a buffer element back into the buffer using `vlPutValid()`, the “oldest” element retrieved by `vlGetNextFree()` is used. There is no way to specify that a different element should be used.

- Because asynchronous I/O operations can complete out of order, the application may need to keep a list of filled elements. When the oldest element is filled, the application can then call `vlPutValid()` to place it back into the buffer, and check to see if any other elements are also ready.

- The same restriction applies to `vlPutFree()` for elements obtained with `vlGetNextValid()` or `vlGetLatestValid()`.

| Caution: Software conversion can severely degrade capture or playback performance.

## Capture and Playback Examples

The following examples of real-time capture and playback are available in ~4Dgifts/examples/dmedia/video/impact:

- `vidtodsk`: video to disk using direct I/O (up to the disk subsystem rate)

- `dsktovid`: disk to video using direct I/O (up to the disk subsystem rate)

- `vidtodsk_aio`: video to disk using asynchronous and direct I/O (up to the disk subsystem rate)

- `dsktovid_aio`: disk to video using asynchronous and direct I/O (up to the disk subsystem rate)

Prev | Table of Contents | Next
Chapter 5. Managing Connections |  | Chapter 7. Blending, Keying, and Transitions