Cheops I1 Streams Library

Functions :

RmanInputOpenStream
RmanInputConnectStream
RmanInputCloseStream
RmanInputDetachStream
RmanInputReadStream
RmanInputIndexStream
RmanInputChangeSampling
RmanInputEnableStream
RmanInputStreamSize
RmanInputConfigNotify
RmanGetTimecode
RmanSetTimecode
RmanGetInputConfig
RmanSetInputConfig

Data Structures :

InputSource
decimation_factor
input_stream_dest
input_stream_size
InputDescCommon
InputCardDesc

This document introduces a stream based software interface used by the Cheops I1 Video Input module. The I1 Input Card is a daughter-card to the M1 Memory module, and it buffers the video data being input in the M1 core memory. This stream model allows simple access to both video data being digitized and video data stored previously on M1. The buffer memory for all streams is maintained using the M1 movie library, and may be accessed (i.e. loaded or stored to disk) through the M1 movie utilities.

Time is maintained using the Stream Time data structures.

An example application using this library is available.

It must be emphasized that this library must be used in conjunction with the RMan library and the Norman Resource Manager. In particular, the RmanInit() function must be called before calling any I1 Stream function that returns a QueueElem *, such as RmanInputReadStream().

Stream Datatypes

There may be up to four input modules in a system, each designated by a unique card id (that of the M1 card to which it is mounted.) Each card has from one to seventeen source devices, designated by a device id. The input source struct provides a unique and simple name for each source. It is defined as a struct (of 32 bits) containing both the card ID and the device ID.

typedef struct {
   unsigned long    device:16,
                    card:16;
} InputSource;

The principal datatype in the software interface, a video stream, is a sequence of color image frames from a single source. This sequence may be either finite or infinite in length, and usually represents a regular temporal sampling. Thus a video stream may be anything from a single frame, or set of key frames, to a continuous (and possibly subsampled) stream of frames. Routines are provided for opening, reading, indexing into, and closing video streams.

Video streams are represented in applications by a pointer to an input_stream_hdr. This header is created by RmanInputOpenStream() or RmanInputConnectStream(), and either destroyed by RmanInputCloseStream() or non-destructively detached by RmanInputDetachStream().

When an application creates a video stream, the number of frames of buffering to be provided is specified. If the application is not going to be processing the data in real time (i.e. at the temporal sampling rate) the number of frames of buffering should be equal or greater than the length of the video stream. When the video stream is "infinite", the stream buffers store the last N frames digitized, where N + 1 is the number of frames in the stream buffers. If the application will be attempting to process the video stream in real time the number of frames of buffering may be as small as two or three, although larger stream buffers will generally produce better results.

The video stream may be accessed by using RmanInputReadStream() to generate an Input Stream Queue Element, a QueueElem structure. An Input Stream Queue Element represents the transfer of one frame in the input stream into local P2 memory when connected into a Transfer Pipe for execution by the Norman resource manager. Multiple Input Stream Queue Elements may be created accessing the same stream. Which frame is selected for transfer may be changed. A frame that hasn't been digitized at the time when the pipe is presented for execution may be selected. The resource manager will wait until the frame has been digitized into the stream buffer before being scheduling that transfer for execution.

In many cases of "real time" processing, the input video data is temporally decimated to provide a lower temporal rate stream for processing. The temporal decimation to be applied is specified using the decimation_factor structure, which contains an array of interframe offsets, the size of the offset array and the current index into the offset array. The array of offsets is used repeatedly as necessary, the value of the last entry in the offset array indicating the delay before digitizing a frame corresponding to the first entry in the array. Regular decimations therefore require only a single entry in the offset array, but complex sampling patterns may also be implemented simply. The offsets are specified, in frames, using 16 bits, which allows delays up to 18 minutes (at 60 fps) between samples.

typedef struct {
        unsigned long   num_offsets;
        unsigned long   index;
        unsigned short  offset[ MAX_SAMPLING_OFFSETS ];
} decimation_factor;

decimation_factor       input_no_decimation = { 1, 0, 1 };
decimation_factor       input_half_rate_decimation = { 1, 0, 2 };
decimation_factor       example_decimation = { 4, 0, 1, 1, 1, 13 };

The last of the pre-defined decimation_factors, example_decimation, shows a temporal decimation where four frames are grabbed consecutively out of every sixteen frames of input video.

The destination buffers in P2 for data from a particular frame are specified using the input_stream_dest structure, which is an array of pointers. The exact number of destination buffers required varies with the input sources configuration type. The two currently defined formats (NTSC_FORMAT and RGB_FORMAT) both use only three channels (entries 0, 1, and 2 in the array.) The input_stream_size structure is used to represent the spatial size of one stream channel. An array of input_stream_sizes is returned by RmanInputStreamSize().

typedef struct {
        unsigned long *chan[ MAX_SOURCE_CHANNELS ];
} input_stream_dest;


typedef struct {
        unsigned long    hor;   /* The horizontal size of a frame  */
        unsigned long    ver;   /* The vertical size of a frame    */
} input_stream_size;

Stream Creation and Destruction

The functions described here are part of the Rman library. Their prototypes are provided in cheops_rman.h.

All applications must either open a stream or connect to a stream already stored in M1 memory, using RmanInputOpenStream() or RmanInputConnectStream(). This returns a pointer to an input_stream_hdr, which can be used to determine the spatial size and other characteristics of the stream. RmanInputReadStream( ) takes a pointer to an input_stream_hdr and returns an Rman QueueElem that represents the transfer of a frame of data from the stream into local memory.

When an application is finished with a stream, it may close the stream using RmanInputCloseStream(), destroying the associated memory buffer if no other applications are currently connected to it. Or it may merely detach from the stream, using RmanInputDetachStream(), leaving the memory buffer intact in memory for later applications.

An Input source may normally only be used by a single application at a time. The exception are applications explictly designed to share video data. The first of these applications to call RmanInputOpenStream() opens the input stream, allocating memory for the buffer and making an entry in the movie directory pointing to it. Later applications attempting to open that input source will "transparently" connect to the stream buffer though the movie directory.

The temporal sampling is specified when a stream is opened, but may be modified using the RmanInputChangeSampling( ) function. The spatial sampling rate, along with many other video input configuration options, may be modified by using the cheops_i1 library. A stand-alone application which provides a convenient user interface for all such video configuration changes is available.


RmanInputOpenStream

Arguments
Returns input_stream_hdr *

If the starting stream_time is an absolute time, this function starts by querying the I1 Address Generator to see if it is possible to access that input source for the selected time span (and reserving it if it is.) If possible, it allocates memory on M1 for the stream buffer, and makes an entry in the movie directory for the buffer using the name provided. If a movie or movies with the requested name already exists, the name is suffixed with a higher version number. The function then informs the I1 Address Generator (AG) about the location of the stream buffers and enables the transfer. Digitizing into the stream buffer will occur when the indicated stream time is reached by the input source.

If the starting stream_time is TIME_IMMEDIATE, this function starts by querying the I1 Address Generator to see if it is possible to access that input source. If possible, it allocates memory on M1 for the stream buffer, and makes an entry in the movie directory for the buffer using the name provided (same as absolute time case). A later call to RmanInputEnable() is required to start the Address Generator digitizing data into the stream buffer. This allows applications to decouple the stream open from the start of digitizing when using relative time.

If, in either case, it is not possible access the specified input source (either because it is in use or doesn't exist) the movie directory is checked to see if a buffer with the name provided has already been created. If such a buffer exists, it is opened and used. If multiple buffers with the name and a version suffix are present, the one with the highest version number is used. It is assumed that such a buffer was created by another instance of this application, and the stream will be shared. This is referred to as a "transparent connect".

The movie directory entry for the stream buffer being used is modified to increment the "open_links" field, used by RmanInputCloseStream(). Finally, this function builds an input_stream_hdr structure for the stream. A pointer to this structure is returned to the application.

I suggest the following conventions for naming the stream buffers :

  1. If the stream is infinite and uses a periodic and regular temporal decimation factor (or none at all), the name should begin with stream_buffer.
  2. If the stream is not infinite, or uses a strange decimation factor, the name should not begin with stream_buffer, but rather some application dependent name.
  3. The name should always be suffixed by which input card and device was used (i.e. stream_buffer_c0d3, for card 0, device 3.)
  4. Multiple versions of the same filename are maintained by suffixing a version number (i.e. stream_buffer_c0d3_v3.) Version 0 has no suffix, and the highest version is assumed to be the newest data.


RmanInputConnectStream

Arguments Returns input_stream_hdr

Checks the M1 movie directory to see if the indicated buffer exists. If so, it is opened, and the frame in the buffer with the earliest stream_time is selected for transfer. The "open_links" attribute of the movie is incremented. An input_stream_hdr structure is then built for the stream. A pointer to this structure is returned to the application on succesful completion.

This function is provided for use by applications that assume that the video data they are procesing was previously digitized and stored. Using this function ensures that a previously stored data is used.


RmanInputCloseStream

Arguments Returns void

Destructively closes a stream created with RmanInputOpenStream(). The number of applications using the stream is indicated by the open_links field of the associated movie structure. If only one application is using the stream, the memory used for the stream buffer is also deallocated. If more than one application is using the stream, the open_links attribute is decremented but the buffer memory will not be freed. If this function is called with an Input Stream Queue Element that was created using the RmanInputConnectStream() function, the action is identical to that of RmanInputDetachStream().


RmanInputDetachStream

Arguments Returns void

Nicely detaches from a stream, deallocating the input_stream_hdr but leaving the movie data stored in M1 memory. The open_links attribute of the stream buffer movie will be decremented, but the movie is not deleted even if no other applications are currently connected to it.


Stream Manipulations

These functions support the allowed manipulations on a stream. These are : providing multiple frames at a time, changing the temporal sampling rate, changing the local destination, enabling and disabling the stream. One additional feature provided through the Rman interface is the ability for an application to be notified if the configuration of a particular input source is modified.

RmanInputReadStream

Arguments
Returns QueueElem *

This function allocates space on the Rman heap and generates a QueueElem representing the transfer of a frame of data from the stream buffer of the indicated stream to the P2 local memory indicated.

There is no procedure for deallocating memory objects on the Rman heap, hence this routine has no equivalent function for free'ing the QueueElems. Don't keep generating new QueueElem in the application ! Modify existing ones instead.


RmanInputIndexStream

Arguments
Returns stream_time

Modifies an Input Stream Queue Element to transfer a particular frame from the stream into a particular location P2 local memory. The desired frame may be identified by providing either an absolute or relative stream_time. If selected using absolute time, the frame temporally closest to the stream_time desired is selected for transfer. If two frames are equidistant, the earlier (in time) will be selected.

If the same P2 destination buffers are to be used, a NULL pointer may be passed either for the pointer to the input_stream_dest structure (if all destination buffers remain the same) or for individual pointers within the structure that remain the same.

The absolute stream_time of the frame actually transferred is returned to the caller upon succesful modification of the queue element. If, however, the desired frame has already been deleted from the buffer of an infinite stream (i.e. too far in the past), or the desired frame is outside of the range of an finite stream, an TIME_INVALID value is returned.


RmanInputChangeSampling

Arguments
Returns int

This function modifies an input_stream_hdr to change the temporal sampling rate of the stream. The spatial sampling rate, along with many other video input configuration options, may be modified by using the cheops_i1 library.

In implementation, this function checks to make sure that the stream is associated with a digitizer, then passes a message to the appropriate I1 Address Generator to restart the stream with the new parameters. If not associated with a digitizer, no action is taken and no error is returned.


RmanInputEnableStream

Arguments
Returns int

This function enables the appropriate channels in the address generator, allowing video to be digitized. It is only needed when the stream was created by calling RmanInputOpenStream() with stream_time of TIME_IMMEDIATE. If the stream is not associated with an input source (i.e. a "transparent connect" occured) this function has no effect and returns without an error.

In implementation, this function sends a message to the appropriate I1 address generator (AG) to query the status of the input source and reserve it if available. If it is still available, the information about the stream buffer is passed in a message and digitizing is enabled to occur at the indicated stream time. It is possible that the input source is no longer idle, and this function will fail, returning an RMAN_RSRC_NOT_FREE error.


RmanInputStreamSize

Arguments
Returns int

This function provides the requested information about the frame and stream associated with the input_stream_hdr provided. Any of the other arguments may be NULL, if the application doesn't require that information.


RmanInputConfigNotify

Arguments Returns int

If called with the INSTALL operation, this function installs a callback function that will be called if any changes are made to the configuration of the specified input source. If called with the REMOVE operation, it removes the callback function.

The callback function is defined as returning void, and taking an InputSource as its only argument.


RmanGetTimecode

Arguments Returns stream_time

Returns the current timecode of a Input source. Beware that this function currently only works when the stream library is being used to digitize video from the indicated source.


RmanSetTimecode

Arguments
Returns int

Modifies the timecode of a Input source. Note that this is not effective if the Input source has a timecode type other than TIMECODE_FREE_RUN.


Input Source Configuration Library Routines

The following routines are part of the I1 library. Their prototypes and defines may be found in cheops_i1.h. The configuration of each input source may be altered by several different applications. The state of the current configuration for each input source is stored in a global data structure. The contents of this table may be read and written by any application. A number of the configuration parameters are common across the different sources, and are defined in the InputDescCommon structure (shown below.) A separate structure is defined for each configuration type supported.

typedef struct {
  short  device_present;    /* either TRUE or FALSE      */
  short  config_type;       /* NTSC_FORMAT, RGB_FORMAT, etc... */
  short  resolution_x;      /* x dimension of resolution */
  short  resolution_y;      /* y dimension of resolution */
  long   frame_rate;        /* frame rate, in TIME_FRACTIONS   */
  float  aspect_ratio;      /* hor / ver ratio           */
  short  timecode_type;     /* type of timecode (VITC/LTC/Run) */
  short  interlaced;        /* either TRUE or FALSE      */
  short  median_filtered;   /* either TRUE or FALSE      */
  short  chroma_x;          /* x dimension of chroma channels  */
  short  chroma_y;          /* y dimension of chroma channels  */
  short  h_blank;   /* offset from hor. sync to start of video */
  short  v_blank;   /* offset from ver. sync to start of video */
} InputDescCommon;

typedef union {
  InputDescCommon   common;
  InputDescNTSC     ntsc;
  InputDescRGB      rgb;
  long              raw[ MAX_INPUT_DESC_SIZE ];
} InputCardDesc;

The current configuration of a particular input source may be examined by means of the GetInputConfig() function, which returns a pointer to the configuration structure for that input source. The SetInputConfig() function copies a configuration structure into the global table. In general, applications should not modify the configuration of an input source. They should, however, properly handle a change in the configuration of an input source. The RmanInputConfigNotify() function allows the installation of a routine to be executed after any changes to the configuration of the specified input source.

GetInputConfig

Arguments Returns

Uses a Magic7 system call to get a pointer to the global input configuration table, then indexes into it and returns a pointer to the configuration structure for that source.

SetInputConfig

Arguments Returns

Uses a Magic7 system call to get a pointer to the global input configuration table, indexes into the table and then copies the InputCardDesc structure passed as an argument into the proper entry. It then calls RmanInputReset(), which causes the Norman Resource Manager to notify any applications which have requested notification of input change, using RmanInputConfigNotify().


See an example application using this library. A completely functional (?) example may be found at ${CHEOPS_BASE}/local/src/diag/rman/streams/show.c


Return to Software Index
Return to Cheops Homepage
wad@media.mit.edu
This is a "fix it yourself" page, located at ${CHEOPS_BASE}/WWW/software/i1streams.html