Chapter 2. Parameters

This chapter describes the dmSDK parameter syntax and semantics. These parameters define a number of variables including control values such as the frame rate or image width, and the location of data such as a single video field.

param/value Pairs

The fundamental building block of the dmSDK is the param/value pair (DMpv), as shown here:

typedef struct {
    DMint64 param;
    DMvalue value;
    DMint32 length;
    DMint32 maxLength;
} DMpv;

The param is a unique numeric identifier for each parameter; and the value is a union of several possible types, of which the most common are:

typedef union {
    DMint32   int32;   /* 32-bit signed integer values */
    DMint64   int64;   /* 64-bit signed integer values */
    DMbyte*   pByte;   /* pointer to an array of bytes */
    DMreal32* real32;  /*32-bit floating point value */ 
    DMreal64* real64;  /*64-bit floating point value */
    DMint32*  pInt32;  /*pointer to an array of 32-bit signed integer values */
    DMint64*  pInt64;  /*pointer to an array of 64-bit signed integer values */
    DMreal32* pReal32; /*pointer to an array of 32-bit floating point values */
    DMreal64* pReal64; /*pointer to an array of 64-bit floating point values */
    struct_DMpv*pPv;   /*pointer to a message of param/value pairs*/
    struct_DMpv** ppPv;/*pointer to an array of messages */}DMvalue; 
    

Messages

In the dmSDK, applications communicate with devices using messages. Each message is a simple array of param/value pairs; where the last param in the message is DM_END.

For example, the following is a message that sets image width to 1920 and image height to 1080:

DMpv controls[3];
controls[0].param = DM_IMAGE_WIDTH_INT32;
controls[0].value.int32 = 1920;
controls[1].param = DM_IMAGE_HEIGHT_INT32;
controls[1].value.int32 = 1080;
controls[2].param = DM_END;


Note: A DMpv ends with the DM_END parameter to indicate completion.


Scalar Values

This section shows you how to set and get scalar values.

Set Scalar Values

To set the values of scalar parameters, you must enter the param and value fields of each DMpv and send the result to a device. If the value is valid, the returned length will be 1. If the value is invalid, or if the parameter is not recognized by the device, an error status will be returned and length will be set to -1.


Note: You do not need to set the length or maxLength fields -- they are ignored when setting scalars. However, on return (dmReceiveMessage) a length parameter that equals -1 indicates that this parameter was in error.


For example, to set video timing:

DMpv message[2];
message[0].param = DM_VIDEO_TIMING_INT32;
message[0].value.int32 = DM_TIMING_525;
message[1].param = DM_END;
if( dmSetControls( someOpenVideoPath, message) )
  fprintf(stderr, "Error, unable to set timing\n");

Get Scalar Values

To get scalar values, you again construct a DMpv list, but here you do not need to set the value field. As the device processes the DMpv list, it fills in the value and length fields. If the value is valid, the returned length is 1. If the value is invalid, or the parameter is not recognized by the device, an error status will be returned, and length is set to -1.

For example, to get video timing:

DMpv message[2];
message[0].param = DM_VIDEO_TIMING_INT32;
message[1].param = DM_END;
dmGetControls( someOpenVideoPath, message);
if( message[0].length == 1 )
  printf("Timing is %d\n", message[0].value.int32);
else
  fprintf(stderr, "Unable to determine timing\n");

Array Values

An array in the dmSDK is much like an array in C:

  • value of the DMpv is a pointer to the first element of the array

  • length is the number of valid elements in the array

  • maxLength is the total length of the array

Also, each element increases the length of the array by 1, so an array of four 32-bit integers would require a maxLength of four.

Set the Value of an Array Parameter

To set the value of an array parameter, fill out the param, value, length and maxLength fields. If the values are valid, the returned length will be unaltered. If the values are invalid or if the parameter is not recognized at all by the device, an error status will be returned and length will be set to -1.

For example:

DMreal64 data[] = { 0, 0.2, 0.4, 0.6, 1.0}; 
DMpv message[2]; 
message[0].param = DM_PATH_LUT_REAL64_ARRAY; 
message[0].value.pReal64 = data; 
message[0].length = sizeof(data)sizeof(DMreal64); 
message[1].param = DM_END; 
dmSetControls( someOpenPath, message )


Note: You do not need to set the maxLength field -- it is ignored when setting an array parameter.


In the preceding example, you are free to modify the data array at any time before calling dmSetControls; and you regain that right as soon as dmSetControls returns.

If you have a multithreaded application, your application must ensure the data array is not accessed by some other thread while the SetControls call is in progress.

Get the Size of an Array Parameter

To get the size of an array parameter, set maxLength to 0. The device will fill in maxLength to indicate the minimal array size to hold that value. If the parameter is not recognized by the device, an error status will be returned, maxLength will be set to 0, and length will be set to -1.

DMpv message[2];
message[0].param = DM_PATH_LUT_REAL64_ARRAY;
message[0].length = 0;
message[0].maxLength = 0;
message[1].param = DM_END;
dmGetControls( someOpenPath, message );
printf("Size of LUT is %d\n", message[0].maxLength);

Get the Value of an Array Parameter

To get the value of an array parameter, create an array with maxLength entries to hold the result, and set length to 0. The device will fill in no more than maxLength array elements and set length to indicate the number of valid entries. If the values are invalid or if the parameter is not recognized at all by the device, an error status will be returned and length will be set to -1.

DMint32 data[10];
DMpv message[2];
message[0].param = DM_PATH_LUT_INT32_ARRAY;
message[0].value.pInt32 = data;
message[0].length = 0;
message[0].maxLength = 10;
message[1].param = DM_END;
dmGetControls( someOpenPath, message );
if( message[0].length > 0 )
{
  printf("Received %d array entries\n", message[0].length);
  printf("The first entry is %d\n", data[0]);
}


Note: Your application controls memory allocation. If you want to get the whole array, but do not know the maximum size, you must query for maxLength first, allocate space for the result, and then query for the value.


Pointer Values

The distinction between array values and pointer values in the dmSDK is subtle, but important. Array values are copied when they are passed to or received from a device. Thus, your application owns the array memory and is nearly always free to modify or free it.

A pointer parameter is a special type of array parameter that is used to send and receive data buffers (as arrays of bytes.) Pointer values are not copied. Instead, only the location of the data is passed to the device. The application sends a buffer by calling dmSendBuffer. dmSendBuffer places the controls and buffer pointer in the data payload area and inserts a header on the send queue for the device.

This is much more efficient, but it imposes a restriction: after a pointer value is given to a device, that memory cannot be touched until the device has finished processing it.


Note: For efficient processing, all buffers must be pinned in memory.


For example, the following code fragment shows how a pointer parameter might be initialized to send an image to a video input path:

DMpv message[2];
message[0].param = DM_IMAGE_BUFFER_POINTER;
message[0].value.pByte = someBuffer;
message[0].maxLength = sizeof(someBuffer);
message[1].param = DM_END;
if( dmSendBuffers( someOpenPath, message ) )
  fprintf(stderr, "Error sending buffers\n");

The above SendBuffers call places the message on a queue to be processed by the device, and then returns. It does not wait for the device to finish with the buffer. Thus, even after the call to SendBuffers, the device still owns the image buffer. Your application must not touch that memory until it is notified that processing is complete.

When you send a buffer to be filled, the device uses maxLength to determine how much it may write, and it returns length set to indicate the amount of the buffer it actually used.

When you send a buffer for output, the device will interpret the length as the maximum number of bytes of valid data in the buffer. In this case maxLength is ignored.